学习c++还必须掌握的
文章目录
函数形参带默认值注意
- 给默认值的时候, 是从右向左给, — 与 函数调用堆栈有关, 从右往左压
- 定义可以给出 默认值, 声明也可以
- 无论是定义给还是声明给, 形参默认值只能是一次
- 声明可以分段给
- 声明分段给时, 必须从右往左给
内联函数(inline)和普通函数区别
注意,只是建议,而不是强制
inline只有在release版本下有用,debug没用,还是需要 call 函数
指令
.o文件是看不到符号链接的
最大区别:普通函数调用有开销, 内联函数在编译阶段在函数调用点直接打开,直接省掉开销;内联函数成功将不会有函数符号;不是所有inline都会成为真正的内联函数
objdump -t .o 将不会看到符号链接
函数重载相关问题
-
什么是函数重载?
函数重载是指同一作用域内,函数名相同但参数列表不同的函数
必须是在一个作用域, 如果一个是main里的局部, 一个是全局, 不会发生重载
bool cmp(int a, int b){ ... } bool cmp(const char* a, const char* b){ ... } bool cmp(double a, double b){ ... } main() // 可以正确发生函数重载 { ... cmp(1,2); cmp(2.0,2.3); } main() // 可以正确发生函数重载 { bool cmp(int a, int b); // 加这个声明后, 将不会正确产生重载, 都将调用这个int的cmp ... cmp(1,2); cmp(2.0,2.3); }
-
面试常见坑
一组函数, 函数名相同,参数列表相同, 仅返回值不同, 不是!不是!重载!
-
const 或者 volatile 是怎么影响形参类型的?
函数形参有无const, 都是一个函数符号
后续会讲, 本节课没讲,先挖了个坑 -
解释一下,什么是多态?
静态多态—在编译时期的多态—常见:函数重载, 模板
动态多态—运行时期的多态—常见:虚函数和继承 -
cpp为什么支持函数重载,c不支持?
C++在编译代码产生函数符号时,由函数名和参数列表类型组成,因此支持函数重载。
-
函数重载的调用确定?
在函数调用点,调用哪个函数重载版本在编译时期生成指令时就已确定。
-
cpp和c之间如何相互调用?
cpp是无法直接调用c的代码的, 因为符号链接 规则格式不同
解决办法:int sum(int a, int b); // 改成 extern "C" { int sum(int a, int b); // 使用c写 } // 高级写法: #ifdef __cplusplus extern "C" { #endif int add(int a, int b); #ifdef __cplusplus } #endif
c同样无法直接调用cpp的代码的
给cpp文件的代码 加上 extern “C”, 千万不能c文件里面, c没有那个东西
typeid(变量名).name()
是查看变量类型
const用法
-
const怎么理解?
const修饰的变量 不能再作为左值!!初始化完成后, 不能被修改
-
c和cpp的const区别?
C语言中,const修饰的变量称为常变量,可以不初始化,但最好初始化。
不能作为常量使用C++中,const修饰的变量必须初始化,否则编译不通过。
C++编译时,const修饰的常量值会被替换,因此可用于定义数组大小。
若const变量的初始值是另一个变量,则该const变量成为常变量,与C语言中类似。 -
为什么?
编译方式不同!
c中, const 是被当做一个常量 来编译生成指令的
cpp中, 所有出现const常量名的地方, 都被常量的 初始化 替换了
但是, 如果用变量 赋值给 const, 会退化为 常变量, 因为变量只有运行的时候, 才知道具体值, 因此 替换时,将不是替换常量值, 而是用 替换为变量
也就无法 用于初始数组大小了int main() { const int a = 20; // a = 30; // 这行代码会导致编译错误 int arr[a]; // c中会出错 cpp编译优化为int arr[10] int *p = (int*)&a; *p = 30; printf("%d\n%d\n%d\n", a, *p, *(&a)); // cpp编译优化为 20,*p, 20 cpp不会真正取地址解引用,编译阶段,视为常量, 直接替换 return 0; } // c输出 30 30 30 // cpp输出 20 30 20 // 使用以下方式, 将和c无异, 30,30,30, int b; const int a=b;
-
注意,c中const, 作为左值不能被修改, 但是 可以使用指针 修改内存上的内容
const与一二级指针结合
cpp中, 常量是绝对不能间接或直接 赋给 指针的!!
-
在c中,由于const修饰的都叫做常变量,因此可以通过指针间接修改. 但是cpp中,const修饰作为常量使用时,不能通过一般指针间接修改值,为什么?
因为使用一般指针时,是 int *和const int *的对应,而const int *在cpp中不能修改内存指向的值,只能指针重新指向新的内存。
解决办法: 使用常量指针const int *作为指针
-
const与一级指针结合的两种情况?
const修饰的是离他最近的类型!!!
const int p与 int const p表示:const修饰的类型是int,修饰的表达式是p,即p无法被更改,*p表示&a。
*注意是类型,可不是类型!!
int* const p表示:const修饰的是类型是int*,修饰的表达式是p,即p是常量,即不能指向 别的内存,*p可以被修改。
主要看const在*的前后去对比记忆!
以及双const: const int * const p
-
cpp指针不使用NULL,而是nullptr
-
面试坑!
int a=10;
const int *p=&a;
int *q=p;
第三行类型转换是有错的!! -
一二级指针和const的类型转换公式?重点!
int * 《 const int * 右值赋给左值 这是不行的---错误的
const int * 《 int *可以,因为右边无限制---正确的
int *const 《 int* 左值实际是 int*, const右边无指针,不参与类型,实际是int * 《 int *---正确的
int ** 《int * const *,这实际还是与一级指针结合,两边都把int*去掉---- 错误的
int** 《 const int ** ----错误的,本质是与二级指针结合
const int** 《 int** ---错误的思考为什么,本质是与二级指针结合
int a=10;
int *p=&a;
const int * q=&p;
这是错误的因为,q和p指向的都是p所在的内存
而*p是const int *类型的(二级指针,两个*意义不同,第二个*表示的是这是指针量,第一个*结合前面的是表示类型),也就是说:
const int b=20;
*q = &b;
这在表面上看是可以的,因为左右类型相同,但是实际上,*q也是p,而p是int *普通指针,那些就变成了,int * 《 const int *,显然这是错误的!!
解决办法:那就一开始的p定义为const int *p,第二种方法,结合呗,const int *const*q呗,完美
intconst 《 int** —正确的 本质还是与一级指针结合
对于实际的const与二级指针结合,两边都必须有const!!!!
-
练习题注意看!
int*const* 《 const int**这么看: 首先看const*《*可以 然后int*《const int * 不可以
引用相关
-
引用与指针的区别?重点
引用是一种更安全的指针
引用必须初始化,指针不需要必须
从汇编看,指令是一模一样的
也正因此,引用初始化的右值必须能取地址,不能是数字啥的
引用无多级引用, 只有以及引用 -
引用数组 格式与 大小
sizeof(数组名)->整个数组大小, int*p=数组名, sizeof§->是指针大小, 但是引用, 却是整个数组大小
int (&q)[5] = 数组名;
sizeof(q) 是整个数组大小切记!这是非法的—
int &q = 数组名;
-
左值引用和右值引用?
这个概念, 是被引用的值,是左值还是右值~
左值引用:int a=10; int &b = a;
// a是左值, 是有内存有名字的,值可以修改的
int &b = 10;
// 10是右值, 没内存, 没名字–这是非法的右值引用: c++11 提供了 :
int &&b = 10;
从汇编看, 是多了一步, 把右值先存到一个栈空间(自动产生临时量), 然后 再给 引用
同时:const int &b = 10;
也是可以的, 这两汇编是一样的, 但是区别是, const 修饰的 无法进行修改, 正规右值引用, 可以修改!!一个右值引用变量, 本身是个左值!!
右值引用变量,不能引用左值!!
const, 一级指针,引用的结合使用
-
写一个代码, 在内存的0x00192827 写一个 4字节的 10?
int *p = (int *)0x00192827;//需要强转, 本身是整数 //进化一下, 内存值是整数,也是右值, 则使用右值引用 int *&&p=(int *)0x00192827; 或者 int * const &p=(int *)0x00192827; // 不让地址变
-
结合使用的 非合法 例子
int a = 10; int *p = &a; int *&q = p;// 对不对? int *&q = p; -> int **q = &p; 是一模一样的, 用右边&覆盖左边第二个* 那 const int** <<= int **对吗, 显然不对 int a = 10; int *const p = &a; int *&q = p;// 对不对? p是常量了, 那常量就不能赋给指针了!
new,delete, malloc, free区别
-
区别?
malloc和free 是 c的 库函数, 仅开辟内存, 不初始化.—malloc开辟内存失败,是通过返回值和nullptr作比较.
而 new和delete 是 运算符! new可以在开辟内存是进行初始化.—new开辟失败,是抛出bad_alloc类型的异常来判断.
int *p = (int*) malloc(sizeof(int)); if(p == nullptr) { return -1; } *p = 20; free(p); try { int *p = new int(20); } catch(const std::bad_alloc &e) { } 数组: int *p = (int*) malloc(sizeof(int)*20); free(p); int *p = new int[20]; // 中括号 int *p = new int[20](); // 合法的, 可以全部初始为0 int *p = new int[20](40); // 非法的, 不能给数组初始化具体值 delete[]p; // 重点, 释放数组形式, 后面会讲,留意一下
-
new有几种?
new int(20); //不抛出异常 new (nothrow) int; const int* = new const int (20); // 常量 //定位new new(&data) int (50); // 将指定内存 修改为整型, 并初始化