二、深入学习c++需要掌握的基础知识
一、掌握形参带默认值的函数
- 给定默认值的时候是从右向左给,因为函数在内存中的压栈顺序是按照形参列表的元素从右向左依次向内存中压栈
- 形参是否有默认值对调用效率的问题:如果有一个默认值,在函数调用的过程中会少一条mov指令,多个默认值就是减少了多条指令。如果调用的时候用的是立即数,也会减少mov指令,因为在访问变量的时候会用到mov指令。
- 定义处可以给定形参默认值,声明处也可以给定形参默认值
- 给定形参默认值的时候,不管是定义处给还是声明处给,一个形参的默认值只能出现一次。
以sum
函数为例:
int sum(int a=10,int b=0);//在声明处可以给定默认值
//当然前提是定义出没有给定默认值。
二、掌握inline函数
inline函数和普通函数逇区别:
- 在编译的过程中,没有函数调用的开销(少了call和push等操作),会直接在函数的调用点吧函数的代码展开处理。
- 同时inline函数不会在.ojb文件的符号表中生成相应的函数符号
- inline关键字只是建议编译器把这个函数处理成内联函数,但不是所有的inline声明都会被编译器处理为内联函数
- debug中的inline是不起作用的,因为要方便调试
标准的函数调用过程为:参数压栈。函数栈帧的开辟和回退过程,如果函数作用很简单,会导致函数开销大于函数执行消耗的时间
三、函数重载详解
首先是三个关于函数重载的问题:
-
c++为什么支持函数重载?,为什c语言不支持函数重载?
因为c++代码在编译时产生函数符号的时候是用函数名+参数列表类型组成的,如
sum_int_int
,而c代码产生函数符号的时候只使用函数名表示。 -
函数重载需要注意什么?
- 有不同形参列表的函数要放在同一个作用域中才会发生函数重载,包括定义和声明,在一个作用域中定义了多个函数,在另一个作用域中声明了一个函数,会有限使用更小的作用域中的定义或者声明。
- 同样类型的形参列表加不加const表示一个函数,不会进行函数重载;同时返回值不同但是形参相同的函数也不会进行函数重载,因为函数符号是使用函数名和参数列表类型组成的,没有记录返回类型。
-
C++和c代码之间如何相互调用?
-
c调用c++:在c++源码括在
extern “C”{}
中,即:extern "C"{ int sum(int a,int b){ return a+b; } }
-
c++调用C代码:把c函数的声明括在extern ”C”中
extern "C"{ int sum(int a,int b); }
-
如果是写跨语言的代码,一般会写成一下形式:
#ifdef __cplusplus
extern "C"{
#endif
int sum(int a,int b){
return a+b;
}
#ifdef __cplusplus
}
#endif
这样写在跨语言的时候会非常方便,因为__cplusplus
宏只在cpp代码中有。如果是c的代码就不会使用extern“C”语法,如果是c++代码,则会注意编译的时候是不是以C的形式编译。
四、全面掌握const的用法
两个问题:
-
要怎么理解const?
-
const修饰的变量不能再作为左值,初始化完成后值不能被修改。
-
c++中的const必须初始化,初始化的时候如果用的是立即数,叫做常量,可以用来定义数组的长度;如果初始化的时候用的是变量赋值,因为变量的值只有在运行的时候才会知道,所以此时const修饰的值叫做常变量,此时就不能定义数组的长度了。
-
-
C和C++中const的区别是什么?
- 两者的编译方式不同,C中的const是当做一个变量来编译生成指令的;而c++在编译过程中所有出现const常量名字的地方,都被常量的初始化替换了,如果初始化时用的是变量则与c中的编译方式相同。
以下是const的一个例子:
int main(){
const int a=20;
int *p=(int*) &a;
*p=30;
cout<<a<<" "<<*p<<" "<<*(&a)<<endl;//
//输出的分别是20 30 20
//如果是常变量,即只是不能作为左值,输出的变量就为30 30 30
}
因为const在编译的时候就会把所有的出现const值的位置都设置为初始值,所以上面代码中所有的a都是初始值20,但是仍然可以改变内存中的值,所以*p
中的值为30。
五、掌握const和一二级指针的结合应用
const修饰的量常出现的错误是:
- 常量不能再作为左值 《= 直接修改常量的值
- 不能把常量的地址泄露给一个普通的指针或者普通的引用变量 《= 可以间接修改常量的值
const和一级指针结合的例子:
在C++规范中,const修饰的是离他最近的类型;
如果const的右边没有指针的话,const是不参与类型的。下面列举四种一级指针与const结合的例子:
-
const int *p
int a = 19; const int* p = &a;//const修饰的表达式是*p,*p不能被赋值,但是可以修改p的内容 //可以指向任意int类型的内存,但是不能通过指针间接修改指向内存中的值 p = &b;
const修饰的表达式是p,p不能被赋值,但是可以修改p的内容可以指向任意int类型的内存,但是不能通过指针间接修改指向内存中的值.p的类型是int const *
-
int const* p
int const* p = &a;//const修饰的表达式是*p与上面的情况一致
p的类型是int const *
-
int *const p
int* const p = &a;//p的类型是int* const,const修饰的表达式是p,就是说p不能被赋值,*p可以 *p = b;//p不能再指向别的内存,但是可以通过指针解引用修改内存中的值
p的类型是int*
-
const int *const* p
const int* const p=&a;//上面两种情况的结合,p和*p都不能被改变、
p的类型是int const *
const和二级指针结合的例子:
int const** p
const修饰的是**p,其值不能改变int *const* p
const修饰的是*p,其值不能改变int **const p
const修饰的是p,其值不能改变,但是能改变**p和*p的值
总结const和一级指针、二级指针的类型转换公式:
类型转换 | 是否正确 |
---|---|
int* <- const int* | 错误 |
const int* <- int* | 正确 |
int** <- const int** | 错误 |
const int** <- int** | 错误 |
int ** <- int *const* | 错误 |
int *const* <- int ** | 正确 |
int *const* <- int **:可以看做是*->const*,因为const修饰的是后面的*。
二级指针两边必须都有const才能成立
例题
A错 第三句 int const *->int*错误
B对 int* -> int*
C对 int* -> int*
D对 int* -> int const*
A错 const int** <- int**
B对 int const* <- int*
C对 int** <- int**
D错 int *const* -> int**
E对 int *const* <- const int**
六、掌握c++的左值引用、初识右值引用
用指针引用数组:
int array[5]={ };
int *p=array;
//定义一个引用变量来引用数组array
int (&q)[5]=array;
cout<<sizeof(array);//20
cout<<sizeof(p);//4
cout<<sizeof(q);//20
七、const,一级指针,引用的结合应用
判断题:
A:正确 把引用还原为指针,最后一句就可一写为:int **q=&p;两边都是int的二级指针
B:错误 不能把一个const的内存泄露给一个普通的指针
C:错误 const int**->int**
D:错误 原因如下:
引用和指针一样,如果遇到不清楚的就把引用换成指针。
八、深入理解C++的new
和delete
new和malloc的区别?
delete和free的区别?
而new只需要一句就能做上面的操作:int *p=new int(20);
开辟数组的不同:
一些常识:
new有多少种?
总共四种:
最后一种定位new是在指定位置开辟内存。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律