C++:基础语法

一、命名空间

       在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。

1.定义

       定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对 { } 即可, { } 中即为命名空间的成员。命名空间本质上定义的是域。命名空间可以嵌套,也可以定义其他的命名空间。在多个文件中,可以同时定义同名的命名空间,编译器会将这些命名空间进行合并。

namespace mynamespace
{int a;int b;
}

2.使用

       命名空间有三种使用方式:

       (1)加作用域限定符

       在C/C++中,不同域可以定义同名变量,但是局部优先。‘:’为作用域限定符,假如我们要访问全局变量,只需在变量前加一个‘::’符号即可。

       编译器若要查找一个函数,它的默认查找的顺序是:先局部,再全局域。它不会主动到命名空间去找,除非我们加上作用域限定符之后才会进去查找。

       上图中,编译器现在在局部查找a变量,没有进入命名空间中。不加作用域限定符,就打印0,当加上作用域限定符时,编译器才会到我们指定的命名空间去找。

       (2)直接展开命名空间

       当我们需要重复调用一个命名空间里面的函数时,每一次调用我们就需要指定一下命名空间,多少有点麻烦。我们可以使用下面一条语句:

using namespace mynamespace;

       这条语句意为展开命名空间,意在指示编译器可以进入到这个命名空间去查找。当使用了这条语句之后,查找的优先级:局部>全局>=命名空间。在全局和命名空间同时存在同名函数或变量时,展开了命名空间之后,相当于把命名空间里面的东西释放到了全局中,如果之前全局域中存在了同名函数,那么就会报错。

       当两个命名空间同时展开时,若两个命名空间同时存在同名函数或变量时,编译器就会报错。因此,展开全部的命名空间是有风险的。

       (3)展开指定成员

       那么我们可以使用第三种方式:指定展开某一个。

using mynamespace::a;

       这条语句意为只展开某一个函数或变量,之后调用它时就不需再指定了。

       这种方法解决了直接展开命名空间时可能会引起的命名冲突的问题。

二、C++输入和输出

       在C语言中,我们使用printf、putchar、scanf等函数在屏幕上输出、输入数据,它需要包含stdio.h这个头文件,但是在C++中,我们使用cin、cout来输入、输出数据。

       其中c为console(控制台)的缩写,out为输出的缩写。在C++中,‘<<’这个符号为“流插入操作符”,endl 为 end line 的缩写,意为换行。在C++中,它多了许多智能的特性,编译器会自动识别变量的类型。当我们想要使用 cout 时,直接使用会报错,因为它在 iostream 中被封装到了一个名为 ‘std’ 的命名空间中。我们个人写代码时,可以直接将std展开,因为没人会和我们起冲突。但是在项目中,多个人参与进来时,尽量不要随意全部展开命名空间。

       当我们想要输入一些数据时,可以使用cin,意为从控制台中提取数据。‘>>’为流提取操作符。

       它的操作顺序是从左到右,输入两个数分别放在对应的变量中。

       当然我们也可以使用 printf 等C语言中的函数,iostream中也定义了这些函数。

三、缺省参数

       在C++中,对函数传参时也和C有所不同。它引入了一个新特性,我们可以不对它传值,那么编译器就会使用你默认设置的值。

       这个默认的值是在设计函数接受参数时设置的。当然也可以缺省多个值

       有一点就是不能跳跃着传参,也就是不能传a和c不传b,不能将b空过去,这样编译器会报错。上面是全缺省,也可以半缺省,但是必须是从右往左缺省,否则在调用的时候就会产生歧义,编译器不知道要将值传给谁。

       缺省参数在定义和声明不能同时出现。它只在声明处给。

四、函数重载

       在C语言中,在同一作用域是不允许同名函数出现的。但是在C++中,它可以在同一作用域中出现同名函数。它的名字可以相同,但是它的参数类型、参数个数、参数顺序需要不同,与参数名无关,当参数相同时,参数名不同,这两个函数不构成重载。当我们输入不同的参数时,编译器会自动去匹配参数类型然后调用相应的函数。若两个同名函数定义在了两个命名空间中,我们把这两个命名空间展开,调用这两个函数时,编译器会报错。因为两个函数不在同一个作用域中,不构成重载关系,编译器不会去匹配他们的类型。

       那么为什么C语言不支持重载呢?

       本质上来讲,是编译器对函数名的修饰不同。在C语言中,编译器不对函数名进行修饰,直接通过函数名来匹配。而在C++中,编译器会根据参数的不同对函数名进行不同的修饰,它们的名字可以相同,但是对它们进行的修饰不同,也就是说,在编译和连接之后,它们已经变成了不同名的函数。不同的编译器对函数名的修饰规则不同。

五、引用

1.引用的定义及使用

       在C++中,引入了引用的概念。引用与指针类似,但又不同于指针。

int main()
{int a = 0;int* b = &a;//指针int& c = a;//引用return 0;
}

       在第二条语句中,‘&’为取地址符,‘&a’表示取出变量a的地址,它是在C语言中使用的,而在C++中,它仍然可以使用。但是在C++中,‘&’还有另一个用法是引用,简单来说就是取别名。我们对c操作,实际上就是对a操作。它与指针的区别是不需要再添加解引用操作符 ‘ * ’ 了。它不仅可以对整形、浮点型变量取别名,也可以对指针变量取别名。

int*& e = b;

       对a的任意一个别名取地址,取到的都是a的地址,也就是说a的别名和a的地址都是相同的,a的别名是c,也可以对c取别名,也可以对c的别名取别名,本质还是a。

       在链表的学习中,有许多的函数需要传递二级指针,使用起来不太方便,那么我们就可以给指针取别名传给函数,就不需要再解引用二级指针来改变一级指针的值了,直接改变别名的值即可。

       引用一旦引用了一个变量,就不能再改变引用的对象。它没有空引用的概念。

2.引用和指针变量间引起的权限问题

       要注意,最初创建的变量的权限是最大的,如果最初创建的变量为可读不可写,那么它的引用的权限是不能大于它所引用的变量的,它最多只能可读可写。

        如图,我们使用b来引用经过const修饰的变量a,出现了报错,这就是权限的放大,引用的权限超过了它所指向的变量。a所引用的值是不能改变的,而b却可以改变,这就是权限的放大。

       当我们给b前面加上const时,此时b与a的权限相等,不会报错。

       指针也是如此,当我们写出下面的代码时,也会报错。

int main()
{int a = 0;const int* b = &a;int* c = b;return 0;
}

       这种也是权限的放大,const修饰的是指针指向的值,这个指针指向的值不能改变,而指针变量c也指向了这个值,却可以通过解引用的方式来修改,是权限的放大,因此编译器会报错。

       若const修饰的是整型变量,它不会引发权限放大的问题。

int main()
{const int a = 0;int b = a;b++;return 0;
}

       const修饰的是a的值,a的值不能被改变,但是不影响a赋值给b,b的值怎样改变与a无关,它们分别存储不同的空间,它们的改变不会相互影响。

       来看下面一段代码

       我们又创建了一个变量c来引用a,然后通过c来改变a,这时发现b的值也改变了,并且没有报错,这是因为const限制的只是它修饰的变量,即不能通过b来改变,但是可以改变c的值来间接改变b的值。

       来看下一段代码:

int main()
{double a = 13.14;//const int b = a;int& c = a;
}

       这段代码也是会报错,属于权限的放大。因为a在赋值给b时,由于类型的不同,复制之前就要先做类型转换,而类型转换具有常性,相当于经过了const修饰,这时候引用经过const修饰的变量,就是权限的放大。

       引用与指针的不同点:

       1.在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

       2.引用在定义时必须初始化,指针没有要求。

       3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何
一个同类型实体。

       4.没有NULL引用,但有NULL指针。

       5.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
位平台下占4个字节)。

       6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。

       7. 有多级指针,但是没有多级引用。

       8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。

       9. 引用比指针使用起来相对更安全。

六、内联函数

       在一些函数中,需要调用许多次其他小函数,比如在排序中,要排几千万个数据,就要调用几千万次到几亿次的交换函数,但是每一次调用都要开辟对应的栈帧,开辟栈帧又是有消耗的,在C++中,有了内联函数的概念,它的意思是就是像交换函数这种小的函数但是需要调用的次数非常多,那么就直接将它展开在调用它的函数中,省去了开辟空间的消耗。它与C语言中的宏类似。但是它是由编译器自动实现的,C语言中还需要我们自己去实现一个宏函数,宏函数的实现很困难并容易出错,内联函数就很好的解决了这一点。

       特性:

       1.它是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。

       2.对于编译器而言只是一个建议,不同编译器关于内联函数实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用内联函数修饰,否则编译器会忽略内联函数特性。

       3.不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。
 

七、auto关键字(C++11)

       auto是一种能够自动推到变量类型的关键字,当一个变量的类型难以拼写时,就可以使用auto代替。

int main()
{std::map<std::string, std::string> m{ { "apple", "苹果" }, { "orange","橙子" },{"pear","梨"} };std::map<std::string, std::string>::iterator it = m.begin();while (it != m.end()){//....}return 0;
}

       std::map<std::string, std::string>::iterator 是一个类型,但是该类型太长了,特别容易写错。

直接将它换成auto,非常方便。

       也可以使用typedef来给类型取别名, 但是也有缺陷。

       使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型。

       使用细则

       用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。

       auto*指定了它的对象必须是指针。

       当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

       auto不能推导的情况

       1. auto不能作为函数的参数
       2. auto不能直接用来声明数组
       3.auto在实际中最常见的优势用法就是C++11提供的新式for循环,还有lambda表达式等进行配合使用。

八、基于范围的for循环(C++11)

       对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范
围内用于迭代的变量,第二部分则表示被迭代的范围。

int main()
{int array[] = { 1, 2, 3, 4, 5 };//使用auto、int都可以,auto只是自动推导类型。for (auto e : array)cout << e << " ";return 0;
}

       范围for循环不能改变数组中的值,范围for循环是将数组临时拷贝一份然后遍历这个临时拷贝的数组。改变这个临时数组并不能改变数组中的值。

       注意:

       1.与普通循环类似,可以用continue来结束本次循环,也可以用break来跳出整个循环。
       2.for循环迭代的范围必须是确定的,对于数组而言,就是数组中第一个元素和最后一个元素的范围,即不支持在函数中对传过来的整形指针使用范围for遍历;对于类而言,应该提供begin和end的方法,begin和end就是for循环迭代的范围。

       3.它只支持从头到尾遍历数组。

十、指针空值nullptr(C++11)

       NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

       可以看到,NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,比如:

void f(int)
{cout<<"f(int)"<<endl;
}
void f(int*)
{cout<<"f(int*)"<<endl;
}
int main()
{f(0);f(NULL);f((int*)NULL);return 0;
}

       程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。

       在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void*)0。

       注意:
       1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入
的。

       2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

       3. 为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/641974.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hindawi暴雷出局,Frontiers却积极整改,能否摘掉“水刊”标签?

【SciencePub学术】自从3月Hindawi暴雷后&#xff0c;MDPI和Frontiers也深受牵连&#xff0c;因其发文量太过猖獗&#xff0c;国人占比高&#xff0c;自引率高等因素&#xff0c;这些出版社旗下的期刊均被贴上“水刊”标签。 上期&#xff0c;小编已经详细介绍了MDPI期刊的口碑…

鸿蒙 harmonyos 线程 并发 总结 async promise Taskpool woker(三)多线程并发 Worker

Worker Worker是与主线程并行的独立线程。创建Worker的线程称之为宿主线程&#xff0c;Worker自身的线程称之为Worker线程。创建Worker传入的url文件在Worker线程中执行&#xff0c;可以处理耗时操作但不可以直接操作UI。 Worker主要作用是为应用程序提供一个多线程的运行环境…

目标检测算法是指什么?

一、目标检测算法是指什么&#xff1f; 目标检测算法是计算机视觉领域的一个重要分支&#xff0c;它旨在识别和定位图像中的目标对象。以下是目标检测算法的相关内容&#xff1a; 目标检测的核心问题&#xff1a;目标检测需要解决的两个核心问题是“目标是什么”和“目标在哪里…

如何加盟共享wifi项目?了解套路有哪些?

自共享wifi项目推出在市场火爆后&#xff0c;各路资本都看到了该项目的广阔前景&#xff0c;纷纷开始研发程序&#xff0c;想要趁机分一杯羹。但对于普通人而言&#xff0c;独立研发程序显然不大现实&#xff0c;于是&#xff0c;共享wifi项目如何加盟便成为了绝大多数人最为关…

java异常的捕获

Java内置了一套异常处理机制&#xff0c;总是使用异常来表示错误。 一,使用try……catch来捕获错误 异常是一种class&#xff0c;因此它本身带有类型信息。异常可以在任何地方抛出&#xff0c;但只需要在上层捕获&#xff0c;这样就和方法调用分离了&#xff1a; try {Strin…

机器人自动驾驶时间同步进阶

0. 简介 之前时间同步也写过一篇文章介绍机器人&自动驾驶中的时间同步。在最近的学习中发现一些额外需要阐述学习的内容&#xff0c;这里就再次写一些之前没写到的内容。 1. NTP NTP 是网络时间协议&#xff0c;用来同步网络中各计算机时间的协议&#xff0c;把计算机的时…

[计算机效率] 网站推荐:网盘资源类

4.6 网盘资源类 在数字化时代&#xff0c;网盘资源搜索已成为我们日常生活和工作中不可或缺的一部分。无论是寻找工作资料、学习素材&#xff0c;还是娱乐资源&#xff0c;一个高效、可靠的网盘资源搜索网站都能为我们节省大量时间。今天&#xff0c;我将为大家推荐几个优秀的…

【C++类和对象】日期类的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

华为公司战略规划和落地方法之五看三定工具解析【PPT图片】(内含超级福利)

导言 华为公司最厉害之处就是战略上的高举高打&#xff0c;“吹过的牛都实现了”。支撑华为公司战略从规划到落地的主要工具很多&#xff0c;其中“五看三定”是战略规划时最核心的方法之一。本资料将介绍五看三定的核心精髓。欢迎学习&#xff01; 本材料结合谢宁老师专著《华…

数据结构之顺序表的实现(C语言版)

Hello, 大家好&#xff0c;我是一代&#xff0c;今天给大家带来有关顺序表的有关知识 所属专栏&#xff1a;数据结构 创作不易&#xff0c;望得到各位佬们的互三呦 一.前言 1.首先在讲顺序表之前我们先来了解什么是数据结构 数据结构是由“数据”和“结构”两词组合⽽来。 什…

【Diffusion实战】训练一个diffusion模型生成蝴蝶图像(Pytorch代码详解)

上一篇Diffusion实战是确确实实一步一步走的公式&#xff0c;这回采用一个更方便的库&#xff1a;diffusers&#xff0c;来实现Diffusion模型训练。 Diffusion实战篇&#xff1a;   【Diffusion实战】训练一个diffusion模型生成S曲线&#xff08;Pytorch代码详解&#xff09;…

六西格玛管理培训:我的转变与成长之旅

4月初&#xff0c;我参与了天行健咨询的六西格玛管理培训&#xff0c;这次经历不仅极大地提升了我的工作效率&#xff0c;还帮助我在工作中实现了卓越。现在&#xff0c;我想分享一些我在这次培训中的学习心得和实践经验&#xff0c;希望能对正在寻求提升绩效和卓越之路的大家有…