【C++】引用

1、命名空间

在 C/C++ 中,变量、函数和类都是大量存在的,这些变量、函数和类的名称将存在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染
命名空间使用
命名空间的使用有以下三种方式:
  • 指定命名空间,加命名空间名称及作用域限定符
    std::cout << N1::a << std::endl;
  • 使用 using 将命名空间内的成员引入
    using N2::b;
    std::cout << b << std::endl;
    注意:当使用多个变量时,可能需要导入多次
  • 使用 using namespace 命名空间名称 引入,
    using namespace N3;
    这种方式会展开命名空间的所有内容,减少了多次导入,实质上相当于全局变量。
注意事项
当全局变量 num 与使用 using namespace N4 中的 num 同时以全局作用域存在时,优先选择全局变量 num。
namespace N4 { int num = 100; }using namespace N4; int num = 50; int main(void) { // 输出 50 std::cout << ::num << std::endl; return 0; }

::num 表示使用全局作用域。
建议指定命名空间,不使用 using namespace std 全局展开。
2、缺省参数
缺省参数是指声明或定义函数时为函数的参数指定了一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
缺省参数分类
  • 全缺省参数
void PrintNum(int a = 10, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; }

  • 半缺省参数
void PrintNum(int a, int b = 20, int c = 30) { cout << "a = " << a << endl; cout << "b = " << b << endl; cout << "c = " << c << endl; }

注意事项
  • 半缺省参数必须从右往左依次来给出,不能间隔着给出
  • 缺省参数不能同时在函数声明和定义中出现,只能从二者中选择其中一个 (如果声明和定义中的缺省参数值不一样,那么就会出错,因为不知道选择哪个)
    建议缺省参数出现在函数声明中。
  • 如果使用了半缺省参数,那么在没有缺省参数的地方必须传入数据(ps: 保证编译器可以找到相关的变量)
  • 缺省值必须是常量
  • C 语言不支持该语法
3、函数重载
同一作用域 中,一组函数的 函数名相同参数列表不同(个数不同/类型不同/顺序不同),返回值可相同可不同,我们把这组函数称为重载函数。
名字修饰
【【C++】引用】名字修饰是一种在编译过程中,将函数、变量的名称重新命名的机制,通俗地讲,就是通过某种规则,将函数以及变量的名称重新命名为一个全局且唯一的名称。
  • 为什么 C 语言不支持重载?
    因为 C 语言编译时只是在函数名字前面添加了下划线,在链接时不知道到底去调用哪个函数。
Linux 下,g++ 的名称修饰方法如下:
a、所有编码后的符号都由 _Z 开头
b、如果有作用域符,则在 _Z 之后加上 N
c、接下来是命名空间名字长度 + 命名空间名字类名长度+ 类名
d、如果有作用域符,则以 E 结尾
e、最后加上函数形参符号,int 就是 i,float 就是 f,有几个形参就写几个符号。
比如,Op::Calc::Add(double a, double b) 经过名字修饰以后就是 _ZN2Op4Calc3AddEdd
extern “C”
在函数前加 extern “C”,就是告诉编译器按照 C 语言编译规则(或者说 C 语言的名字修饰规则)来编译。
4、引用
引用不是新定义一个变量,而是给已存在的变量取了一个别名。编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
类型& 引用变量名(对象名) = 引用实体
注意: 引用类型必须和引用实体是同种类型的
引用特性
  • 引用在定义时必须初始化
    即就是必须存在变量,才能对其取别名。
  • 一个变量可以有多个引用
    int a = 10; int& ra = a; int& rra = a;
  • 引用一旦引用一个实体,再也不能引用其他实体。
    int a = 10, b = 20; int& ra = a; int& ra = b;
    这样就会因为重复引用而导致编译出错。
常引用
const int a = 10; const int& ra = a;
const int& rb = 10
使用场景
  • 作形参
    可以达到传值和传地址的效果,如果不想通过形参来改变实参,那么引用前加上 const
  • 作返回值
    不能返回栈空间上(临时变量)的引用,如果一定要以引用类型返回,那么返回值的生命周期必须不受函数的限制(即比函数生命周期长,可以考虑全局变量或者静态变量)。
引用和指针的区别
  • 引用在定义时必须初始化,指针没有强制要求。
  • 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。
  • 没有 NULL 引用,但有 NULL 指针。
  • sizeof 中含义不同:引用结果为引用类型的大小,指针始终是地址空间所占字节个数(32 位平台下占 4 个字节)。
  • 引用自增即引用的实体自增 1,指针自增即指针向后偏移一个指向类型的大小。
  • 访问实体方式不同,指针需要解引用去访问,而引用通过编译器自己处理。
  • 指针使用时需要判空,而引用不需要。
5、内联函数
inline 修饰的函数叫做内联函数,编译时 C++ 编译器会在调用内联函数的地方展开。使用内联函数可以提升程序运行的效率,因为其没有函数压栈的开销。
特性
  • inline 是一种以空间换时间的做法,可以省去调用函数额开销。因此代码很长或者有循环/递归的函数不适宜作为内联函数。
  • inline 对于编译器而言只是一个建议,编译器会自动优化。
  • inline 不建议声明和定义分离,如果分离则会导致链接错误。因为 inline 被展开后,就没有函数地址了,链接就会找不到。

    推荐阅读