施磊老师c++笔记(一)

学习c++还必须掌握的

函数形参带默认值注意

  1. 给默认值的时候, 是从右向左给, — 与 函数调用堆栈有关, 从右往左压
  2. 定义可以给出 默认值, 声明也可以
  3. 无论是定义给还是声明给, 形参默认值只能是一次
  4. 声明可以分段给
  5. 声明分段给时, 必须从右往左给

内联函数(inline)和普通函数区别

​ 注意,只是建议,而不是强制
​ inline只有在release版本下有用,debug没用,还是需要 call 函数 指令
​ .o文件是看不到符号链接的
​ 最大区别:普通函数调用有开销, 内联函数在编译阶段在函数调用点直接打开,直接省掉开销;内联函数成功将不会有函数符号;不是所有inline都会成为真正的内联函数
​ objdump -t .o 将不会看到符号链接

函数重载相关问题

  1. 什么是函数重载?

    函数重载是指同一作用域内,函数名相同但参数列表不同的函数

    必须是在一个作用域, 如果一个是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);   
    }
    
  2. 面试常见坑

    一组函数, 函数名相同,参数列表相同, 仅返回值不同, 不是!不是!重载!

  3. const 或者 volatile 是怎么影响形参类型的?

    函数形参有无const, 都是一个函数符号
    后续会讲, 本节课没讲,先挖了个坑

  4. 解释一下,什么是多态?

    静态多态—在编译时期的多态—常见:函数重载, 模板
    动态多态—运行时期的多态—常见:虚函数继承

  5. cpp为什么支持函数重载,c不支持?

    C++在编译代码产生函数符号时,由函数名和参数列表类型组成,因此支持函数重载。

  6. 函数重载的调用确定?

    在函数调用点,调用哪个函数重载版本在编译时期生成指令时就已确定。

  7. 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用法

  1. const怎么理解?

    const修饰的变量 不能再作为左值!!初始化完成后, 不能被修改

  2. c和cpp的const区别?

    C语言中,const修饰的变量称为常变量,可以不初始化,但最好初始化。
    不能作为常量使用

    C++中,const修饰的变量必须初始化,否则编译不通过。
    C++编译时,const修饰的常量值会被替换,因此可用于定义数组大小。
    若const变量的初始值是另一个变量,则该const变量成为常变量,与C语言中类似。

  3. 为什么?

    编译方式不同!
    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;
    
  4. 注意,c中const, 作为左值不能被修改, 但是 可以使用指针 修改内存上的内容

const与一二级指针结合

cpp中, 常量是绝对不能间接或直接 赋给 指针的!!

  1. 在c中,由于const修饰的都叫做常变量,因此可以通过指针间接修改. 但是cpp中,const修饰作为常量使用时,不能通过一般指针间接修改值,为什么?

    ​ 因为使用一般指针时,是 int *和const int *的对应,而const int *在cpp中不能修改内存指向的值,只能指针重新指向新的内存。

​ 解决办法: 使用常量指针const int *作为指针

  1. 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

  1. cpp指针不使用NULL,而是nullptr

  2. 面试坑!

    int a=10;
    const int *p=&a;
    int *q=p;
    第三行类型转换是有错的!!

  3. 一二级指针和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!!!!

  1. 练习题注意看!

    int*const*  《  const int**这么看:
       首先看const*《*可以
       然后int*《const int *  不可以
    

引用相关

  1. 引用与指针的区别?重点

    引用是一种更安全的指针
    引用必须初始化,指针不需要必须
    从汇编看,指令是一模一样的
    也正因此,引用初始化的右值必须能取地址,不能是数字啥的
    引用无多级引用, 只有以及引用

  2. 引用数组 格式与 大小

    sizeof(数组名)->整个数组大小, int*p=数组名, sizeof§->是指针大小, 但是引用, 却是整个数组大小
    int (&q)[5] = 数组名;
    sizeof(q) 是整个数组大小

    切记!这是非法的—int &q = 数组名;

  3. 左值引用和右值引用?

    这个概念, 是被引用的值,是左值还是右值~
    左值引用: int a=10; int &b = a; // a是左值, 是有内存有名字的,值可以修改的
    int &b = 10; // 10是右值, 没内存, 没名字–这是非法的

    右值引用: c++11 提供了 : int &&b = 10; 从汇编看, 是多了一步, 把右值先存到一个栈空间(自动产生临时量), 然后 再给 引用
    同时: const int &b = 10; 也是可以的, 这两汇编是一样的, 但是区别是, const 修饰的 无法进行修改, 正规右值引用, 可以修改!!

    一个右值引用变量, 本身是个左值!!
    右值引用变量,不能引用左值!!

const, 一级指针,引用的结合使用

  1. 写一个代码, 在内存的0x00192827 写一个 4字节的 10?

    int *p = (int *)0x00192827;//需要强转, 本身是整数
    
    //进化一下, 内存值是整数,也是右值, 则使用右值引用
    int *&&p=(int *)0x00192827;
    或者
    int * const &p=(int *)0x00192827; // 不让地址变
    
  2. 结合使用的 非合法 例子

    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区别

  1. 区别?

    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;  // 重点, 释放数组形式, 后面会讲,留意一下
    
    
    
  2. new有几种?

    new int(20);
    
    //不抛出异常
    new (nothrow) int;
    
    const int* = new const int (20); // 常量
    
    //定位new
    new(&data) int (50); // 将指定内存 修改为整型, 并初始化
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值