前言:本文章主要用于个人复习,追求简洁,感谢大家的参考、交流和搬运,后续可能会继续修改和完善。
因为是个人复习,会有部分压缩和省略。
一、namespace命名空间
C++使用命名空间(namespace)来避免命名冲突。
在定义一个命名空间后,在外部未经处理是不可调用其中内容的。
命名空间会定义一个新的域,命名空间中的内容局限于该命名空间中。在链接时,相同命名空间里的东西会被合并到一起。同一域里不能定义同名的变量(不能重复定义)
命名空间可以嵌套定义。
只有展开命名空间或指定域时,才可以使用命名空间里的东西
命名空间使用方式:
1.加命名空间名称及作用域限定符。(在局部:std::cin)
2.使用using将命名空间中成员引入。(在全局:using std::cin;)
3.使用using namespace命名空间名称引入。(在全局:using namespace std;)
using namespace std;的意义:C++为了防止命名冲突,把标准库的东西都放进了std这个命名空间,这个代码的意思是展开了std该命名空间,可以使用该域里的所有东西。
使用命名空间的建议:
1.在项目中,尽量不要用using namespace std;因为可能会导致命名冲突,库里有些我们不了解的东西可能会与我们自己定义的变量名冲突。
2.一般日常练习可以使用using namespace std;
3.项目中,常用指定命名空间访问+展开。例如:using std::cin;
二、C++的输入与输出
C++中我们不需要给输入输出指定类型,因为它们可以自动识别类型
C++的输入与输出:cin、cout
头文件:<iostream>
自动识别类型的原理:函数重载+运算符重载
cout标准输出对象:控制台
cin标准输入对象 :键盘
cin与cout需要结合运算符来使用
>>:流提取运算符。提取输入的东西,并放到变量中。也就是我们所说的输入。
<<:流插入运算符。将变量插入到控制台中。也就是我们所说的打印。
平时建的项目都是控制台应用程序,是和控制台交互的。
实际上cout和cin分别是ostream和istream类型的对象,它们可以自动识别类型。
注意:
1.打印char*类型时,cout无法判断是指针还是字符串
2.流提取和流插入的运算符优先级是高于==的
三、缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值。
缺省参数分为全缺省参数和半缺省参数(部分参数缺省)。
缺省参数的特点:
1.缺省参数不能在声明和定义中同时出现,建议在声明中给。
2.因为传参数时是从左往右给的,所以给缺省时是从右往左给,并且不能有间隔。
3.缺省值必须是常量或者全局变量。
四、函数重载
函数重载即一词多义,让使用更加方便
函数重载的要求:
1.在同一作用域中
2.同名函数
3.参数列表必须不同(参数的个数或类型或顺序)
注意:
只有返回值不同时,不构成重载
只有形参的名称不同,也不构成重载
1.下面两个函数能形成函数重载吗?有问题吗或者什么情况下会出问题?
以下是运行报错
不构成函数重载,两个Func的区别是有没有给形参a缺省值,想构成函数重载对于参数的条件是: 形参的个数、类型或顺序不同,这里不符合重载的条件,所以两个其实是同一个函数,Func重复定义,报错无法运行。
当一个参数为int,一个为int&,两函数构成重载,但是调用时会有歧义。
以下这种情况构成重载,第一个add可以运行成功,但是第二个不可以
void add(int x = 0,int y = 0,int z = 0)
{
return x+y+z;
}
void add(int x = 0, int y = 0)
{
return x+y;
}
int main()
{
add(1,2,3);
add(1,2);
return 0;
}
六、引用
引用不是新定义一个变量,而是给已存在的变量取别名,编译器不会为引用出来的别名开辟内存空间,而是让别名和它引用的变量共用一块内存空间。(可通过取地址看出)
类型&引用变量名(对象名) = 引用实体;
引用类型和引用实体必须是同种类型。
引用的特性:
1.引用在定义时必须初始化(不能写成NULL)
2.一个变量可以有多个引用
3.引用一旦引用一个实体,就不能再去引用其他实体。(即作为一个变量的别名后,不能再作为其他变量的别名)。
引用在做参数或做返回值时,可以减少拷贝,提高效率,可以更好地节省空间和时间,尤其是在处理大的对象时。
深拷贝时不用引用的话,效率会比较低。
引用还可以用作swap交换
void swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
指针和引用的区别
指针和引用基本相似,但二者在使用场景、语法特性、底层原理上还是有区别的。
引用和指针的不同点:
1.引用在定义时必须初始化,指针没有要求。
2.引用在初始化引用一个实体后,就不能再引用其他实体了,而一般指针可以在任何时候指向任何一个同类型实体。
3.没有空引用,但是有空指针。
4.在sizeof中的定义不同,计算引用的结果为其所引用类型的大小,而指针始终是地址空间所占的字节数(4/8)。
5.引用自增时,是引用的实体自增1,指针则是向后偏移一个类型的大小。
6.有多级指针,但是没有多级引用。
7.访问实体的方式不同,指针需要显式解引用来访问,引用是编译器自己处理,大多可以直接访问。
8.引用比指针更安全。
9.指针需要开辟空间,引用不用开辟空间(实际在其汇编实现中,引用的底层是有类似指针存地址的方式做处理的)
10.一般传参时,引用的效率更高。当参数和返回值是比较大的变量时,传引用传参和传引用做返回值还可以提高效率,只要符合条件,尽量用引用传参传返回值,并且可以避免一些深拷贝
在链式结构时,引用无法代替指针。因为引用定义时必须初始化,并且引用不能改变指向。
从语法角度而言,引用没有开空间,指针开了4/8个字节。在底层实现的角度,引用的底层是用指针实现的。
注意:
1.是否能引用要注意访问权限大小。权限可以缩小,但是不能放大。
const int a = 10;//只读,是属于不能修改的 int& ra = a;//这样做是不行的,ra引用a属于权限放大。 //改成const int &ra = a;这样可以 int b = 10; int& rb = b;//可以 const int& crb = b;//属于权限的缩小,可以 int c = 10; double d = 1.11; d = c;//可以,这里属于隐式类型转换
//权限的平移 int a = 10; int& b = a; //权限放大 const int c = 20; int& d = c;//不可以 //应该写成 const int& d = c; //这样不可以 d = 10; int e = 5; const int& f = e;//可以,属于权限的缩小
2.const&有很强的接收度。一般使用数据时,即使有const,也无关权限,权限的放大和缩小只针对引用和指针。
int i = 1; double b = i;//这里会发生隐式类型转换 double& r = i;//不可以,因为这种类型转换中间会产生一个临时变量的,临时i把值给临时变量,临时变量把给r,而临时变量具有常性,r属于非const的,这里属于权限放大,是不允许的 const double& rr = i;//可以
3.
int a = 10; int& b = a; int x = 15; b = x; 这里不是把b作为x的别名,而是把x的值赋给b所引用的实体(a)。 (b已经是a的实体,就不能再用它去引用其他人了)
七、隐式类型转换
int c = 10;
double d = 1.11;
d = c;//可以,这里属于隐式类型转换
不是直接把c给d,而是产生一个临时变量,然后把临时变量给d
int c = 10;
double d = 1.11;
d = c;//可以,这里属于隐式类型转换
double& rc = c;//不可以
const double& brc = c;//可以
//这里rc、brc引用的并不是c(即并不是c的别名),而是c产生的临时变量,临时变量具有常性,所以加const。(该临时变量类型为double)
强制类型转换和隐式类型转换基本一样,因为他们都会产生临时变量,它们都是不改变c本身的,都是产生临时变量的。并且它们转换都不会影响c(不论是c的类型还是什么)。
int& add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = add(1,2);//这样是编不过的
return 0;
}
此时临时变量的类型为int&。传值返回返回的是c的拷贝,传引用返回返回的是c的引用
实际上,如果出了函数作用域,返回变量就不存在了,不能用引用返回
传值返回也会给值创建一个临时变量,例如return c;会创建一个c的临时变量,然后将临时变量返回。那么怎么证明它产生了临时变量呢?
int add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = add(1,2);//这样是编不过的
const int& ret = add(1,2);//这样可以
return 0;
}
因为临时变量具有常性,所以加了const才能编过
当参数和返回值是比较大的变量时,传引用传参和传引用做返回值还可以提高效率,只要符合条件,尽量用引用传参做返回值,引用传参还可以避免一些深拷贝