一、形参带默认值的函数
二、inline内联函数
三、const用法
1.const修饰的变量不能作为左值,初始化完成后,值不能修改
2.C与C++中const的区别是:编译方式不同
C:作为一个变量来编译生成指令,C中的const可以不必被初始化,能正常编译,不叫常量,叫常变量。
const int a = 20; int array[a] = {};//不可以用作数组的索引,编译会报错,因为是个变量,在运行的时候才会复赋值 int* p = (int*)&a; *p = 30; printf("%d,%d,%d\n", a, *p, *(&a)); //输出结果:30 30 30
C++:所有const常量名字的地方,都被常量的初始化替换了,C++的const必须被初始化,不初始化会报错,可以说是个常量。
const int a = 20; int array[a] = {};//可以用作数组的索引,因为是个常量 int* p = (int*)&a; *p = 30; //20 30 20 printf("%d,%d,%d\n", a, *p, *(&a)); //输出结果:20 30 20
这个时候a的内存已经改成了30,而C++在编译的时候已经把a替换成20这个字面量了,所以其实可以说是常量
如果用一个变量来初始化,那么因为初始值不是一个立即数,所以此时的a是个常变量,可以说是个变量
int b = 20; const int a = b; int array[a] = {};//不可以用作数组的索引,编译会报错,因为是个变量,在运行的时候才会复赋值 int* p = (int*)&a; *p = 30; printf("%d,%d,%d\n", a, *p, *(&a)); //输出结果:30 30 30
四、函数重载
五、左值引用与右值引用
1.引用是一种更安全的指针,引用必须初始化,但指针可以不初始化。
int a = 10; 00007FF7A6A0236E mov dword ptr [a],0Ah int* p = &a; 00007FF7A6A02375 lea rax,[a] 00007FF7A6A02379 mov qword ptr [p],rax int& b = a; 00007FF7A6A0237D lea rax,[a] 00007FF7A6A02381 mov qword ptr [b],rax *p = 20; 00007FF7A6A02385 mov rax,qword ptr [p] 00007FF7A6A02389 mov dword ptr [rax],14h
根据汇编代码可以看出,引用和指针都是通过操作地址来进行的,所以定义引用变量时需要初始化并且用于初始化的这个值一定要能取地址,所以int & c=20;这个表达式是错的
2.引用只有一级引用,没有多级引用,指针可以有一级指针,也可以有多级指针
3。定义一个引用变量和定义一个指针变量,其汇编指令是一模一样的;通过引用变量修改所引用内存的值,和通过指针解引用修改指针指向的内存的值,其底层指令也是一模一样的 。
左值与右值:
左值:有内存,有名字,值可以修改 右值:没内存,没名字,直接放入寄存器
int a = 10; 00007FF75D551EFE mov dword ptr [a],0Ah int& b = a; 00007FF75D551F05 lea rax,[a] 00007FF75D551F09 mov qword ptr [b],rax //int& c =20; //C++提供了右值引用 int&& C = 20; 00007FF75D551F0D mov dword ptr [rbp+64h],14h 00007FF75D551F14 lea rax,[rbp+64h] 00007FF75D551F18 mov qword ptr [C],rax C = 30; 00007FF75D551F1C mov rax,qword ptr [C] 00007FF75D551F20 mov dword ptr [rax],1Eh /* int temp =20; temp -> b */ const int& d = 20; 00007FF75D551F26 mov dword ptr [rbp+0A4h],14h 00007FF75D551F30 lea rax,[rbp+0A4h] 00007FF75D551F37 mov qword ptr [d],rax //d=30;
从反汇编可以看到,右值引用专门用来引用右值类型,指令上,可以自动产生临时量,然后直接引用零适量,右值引用与const int&基本相同,但不同的是右值引用变量可以直接修改,但const int&不行
int &e=C;是可以的,一个右值引用变量,本身就是一个左值,但是int &&e=c;是不可以的,一个右值引用必须引用一个右值,不能是一个左值,因为右值引用引用的是右值,而右值是直接输入到寄存器里面的,必须生成一个临时量
六、const与一、二级指针结合
1.const 修饰的量常出现的错误是:
1)常量不能再作为左值,即直接修改常量的值
2)不能把常量的地址泄露给一个普通的指针或者普通的引用变量,即间接修改常量的值
2. const 与一级指针的结合
C++的语言规范:const修饰的是离他最近的类型。 int a = 20;
const int* p = &a;//==>*p=20 错误 p=&b 正确 //此时int本身就是一个类型,所以const 修饰的是int,所以const修饰的表达式是*p,所以不能通过指针间接修改指向的内存的值 ,但是p这个指针本身没有被const修饰,所以可以赋予其不同int 类型的内存地址
int a = 20;
int* const p=&a;//==> p=&b 错误 *p=20 正确
//此时这个指针p是常量,不能再指向其他内存,但是*p不是,所以可以通过指针解引用的方式修改指向内存里的值
总结const与指针的类型转换公式:
int* <== const int* 是错误的 const int* <== int* 是可以的
int** <== const int** 是错误的! const int** <==int** 是错误的
const与二级指针的结合两边必须都有const,不能一边有const,一边没有const
int** <== int* const* 是错误的 int* const* <== int** 是可以的
以上两个其实不是二级指针的转换而是一级指针的转换,其实只考虑const后面的*即可,故可以转换为:
int* <== const int* 是错误的 const int* <== int* 是可以的 这两种来比较
int* q1 = nullptr; int* const q2 = nullptr; std::cout << typeid(q1).name() << std::endl; std::cout << typeid(q2).name() << std::endl; //输出结果: int* int* //const如果右边没有指针*的话,const 是不参与类型的 int a = 10; int* p1 = &a; const int* p2 = &a; //const int* <== int* int* const p3 = &a; // int* <== int* int* p4 = p3; //int* <== int*
3. const 与二级指针的结合
int a = 10; int* p = &a; int** q = &p;
此时的二级指针q有三种情况:q *q **q
const int **q ; 此时离const最近的类型是int ,故**q不能被赋值,即a的值不能被改变,但p和q的值可以被改变
int *const*q; 此时离const最近的类型是int*,故*q不能被赋值,即p的值不能被改变,但q和a的值可以被改变
int **const q; 此时离const最近的类型是int**,故q不能被赋值,即q的值不能被改变,但p和a的值可以被改变
至于const int **q=&p;则是错误的,因为该表达式如果成立则有可能导致把一个常量的地址泄露给普通的指针,此时可以说*q就是p,而*q此时被const修饰,所以是常量的地址泄露给了p,p可以修改,故不成立。
七、const、指针、引用的结合使用
不能判断的时候可以将引用&转换成指针来理解:即左边把引用&换成指针*,右边取地址加上&
标签:const,int,30,C++,基础知识,概述,引用,20,指针 From: https://www.cnblogs.com/treelakes/p/18526202