C/C++11 语法/概念易错总结(1)

文章目录

  • 缺省参数
  • 函数重载
  • 引用
  • 引用和指针
  • 内联
  • 宏的优缺点
  • auto
  • 范围for
  • NULL和nullptr

缺省参数

  1. 半缺省参数必须从右往左依次来给出,不能间隔着给
void Func(int a, int b = 10, int c = 20)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }
  1. 缺省参数不能在函数声明和定义中同时出现
  2. 缺省值必须是常量或者全局变量

函数重载

C++函数重载至少要满足,函数的返回值、函数的参数个数、函数的参数类型、函数不同参数类型的顺序至少有一个不一样 ;

原理:

生成可执行程序需要经过:预处理、编译、汇编、链接 四个阶段 。
在C语言专用的编译器中在: C语言 ——> 汇编代码 这个过程将函数名直接转为汇编代码 ;
而C++专用的编译器中在:C/C++语言 ——> 汇编代码 这个过程将函数名经过修饰转为汇编代码,Linux g++ 编译器修饰的方法为(不同的平台、编译器有不同的修饰方法,但都能支持C++重载的条件):

_Z+函数长度+函数名+类型首字母

C/C++11 语法/概念易错总结(1)_第1张图片
C/C++11 语法/概念易错总结(1)_第2张图片

引用

  1. 引用在定义时必须初始化;
  2. 引用一旦引用一个实体,再不能引用其他实体;
  3. 引用只能引用变量 ;
  4. 传引用返回要保证引用对象没有被销毁 (函数在运行结束后,函数生命周期内定义的变量的空间就会归还给操作系统处理);
  5. 能用引用传参和传返回值尽量用,因为不用拷贝运行效率更高;
  6. 在底层实现上实际是有空间的,因为引用是按照指针方式来实现的

引用和指针

引用和指针的不同点:

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
    (在汇编代码层面原理相同)
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32
    位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全

内联

  1. 内联是一种建议,编译器不一定采用
  2. 使用内联函数,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率
  3. 内联函数定义和声明不要分离,因为展开是指函数体的展开,分离会导致链接错误,inline被展开,就没有函数地址了,链接就会找不到;

宏的优缺点

优点:
提高代码的可读性和可维护性:宏可以将一系列重复的代码片段封装起来,使代码更加简洁和易于理解。
增加代码的灵活性:宏可以根据不同的参数生成不同的代码,使代码具有更强的适应性和灵活性。
提高代码的复用性:宏可以在不同的地方多次使用,避免了重复编写相同的代码。
提高代码的效率:宏在编译时会被展开,不会引入额外的函数调用开销,可以在一定程度上提高代码的执行效率。

缺点:
宏的使用容易出错:宏展开后的代码可能会与预期不符,容易引入难以发现的错误。
宏的调试困难:宏在编译时展开,调试时无法直接查看宏展开后的代码,增加了调试的难度。
宏的可读性较差:宏展开后的代码可能会变得冗长和难以理解,降低了代码的可读性。
宏的滥用可能导致代码的可维护性下降:过度使用宏可能会导致代码的可维护性下降,增加了代码的复杂性和难度。

C++有哪些技术替代宏?

  1. 常量定义 换用const enum
  2. 短小函数定义 换用内联函数

auto

  1. 编译器在编译期会将auto替换为变量实际的类型
  2. 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须
    加&
  3. 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错
  4. auto不能作为函数的参数
  5. auto不能直接用来声明数组

范围for

范围for的使用条件:

  1. 容器或数组必须是一个可迭代的对象,即它必须实现了begin()和end()方法,用于返回迭代器指向容器或数组的起始和结束位置。

  2. 迭代器类型必须支持解引用操作,以便可以访问容器或数组中的元素

  3. 对于数组,range-based for循环会自动推导出数组的大小,并使用索引来遍历数组的每个元素。

  4. 对于数组需要知道范围

void TestFor()  // 正确
{
int array[] = { 1, 2, 3, 4, 5 };
for(auto& e : array)
     e *= 2;
for(auto e : array)
     cout << e << " ";
return 0;
}



void TestFor(int array[])  // 错误
{
    for(auto& e : array)
        cout<< e <<endl;
}

for循环原理:

编译器会根据range-based for循环的语法,将其转换为一个普通的for循环。对于容器类型,编译器会调用容器的 begin() 和 end() 方法来获取容器的起始和结束迭代器。这些迭代器用于遍历容器中的元素。对于数组类型,编译器会自动推导出数组的起始和结束位置,并使用索引来遍历数组的每个元素。在每次迭代中,编译器会将当前元素赋值给循环变量,然后执行循环体内的代码。

NULL和nullptr

  1. NULL是宏,定义为 ((void*)0) , nullptr为关键字
  2. nullptr和NULL所占空间相同

你可能感兴趣的:(c语言,c++,个人学习)