【C++】缺省参数 函数重载 内联函数

文章目录

      • 缺省参数
        • 概念
        • 全缺省参数
        • 半缺省参数
        • 注意事项
      • 函数重载
        • 概念
        • 名字修饰——C++为什么支持函数重载
        • extern "C"
      • 内联函数
        • 概念
        • 特性

缺省参数

概念

首先明确一点,缺省是什么意思?

百度百科给的答案是缺省,即系统默认状态,意思与“默认”相同

缺省参数是声明或定义函数时为函数的参数指定一个默认值

在调用该函数时,如果没有指定实参,也就是没有传对应的参数,则采用该默认值,否则使用指定的实参。

举一个最简单的例子:

void f(int a = 0) {
	cout << a << endl;
}

int main() {
	f(); // 没有传参时,使用参数的默认值
    f(10); // 传参时,使用指定的实参
    return 0;
}

第一次调用 f 打印出来的是 0 ,因为没有传参数,默认 a = 0

第二次调用 f 打印出来的是 10,因为传的参数是 10,这时给的缺省值就不起作用了。


全缺省参数

全缺省参数是指声明或定义函数时所有参数都给定缺省值。

例如:

void f(int a = 0, int b = 0, int c = 0) {
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
}

int main() {
    f();       //1
    f(1);      //2
    f(1, 2);   //3
    f(1, 2, 3);//4
    return 0;
}

上面四处对 f 函数的调用都是正确的,

第一处打印结果是 0 0 0

第二处打印结果是 1 0 0

第三处打印结果是 1 2 0

第四处打印结果是 1 2 3

可见,参数全缺省是最安全的。


半缺省参数

全缺省参数是指声明或定义函数时部分参数给定缺省值。

例如:

void f(int a, int b = 10, int c = 20) {
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    cout << "c = " << c << endl;
}

int main() {
    f(1);      //1
    f(1, 2);   //2
    f(1, 2, 3);//3
    return 0;
}

注意,半缺省参数意味着部分参数没给缺省值,这也就意味着必须要有实参,所以调用函数时需要注意。


注意事项

  1. 由于实参是从左向右传给形参的,以 2 处函数调用为例,打印结果是 1 2 20 ,所以对应的,半缺省参数必须从右往左依次来给出,不能间隔着给

  2. 如果函数的声明和定义是分开的,那缺省函数不能在函数声明和定义中同时出现,比如:

//.h
void TestFunc(int a = 10); //函数声明

// .cpp
void TestFunc(int a = 20)  //函数定义
{}

image-20220810135228815

  1. 缺省值必须长期存在。什么意思呢?上面函数参数的缺省值给的都是常量,在程序整个的生命周期中都存在,当然我也可以不传常量,传全局变量也可以:

    【C++】缺省参数 函数重载 内联函数_第1张图片


函数重载

概念

直接上代码:

int Add(int left, int right) {
	return left + right;
}

double Add(double left, double right) {
	return left + right;
}

long Add(long left, long right) {
	return left + right;
}

C++支持在同一作用域中声明定义同名函数,这些函数的特点是形参列表不同,包括参数个数参数类型参数顺序不同。这些同名函数就构成函数重载。

例如上面的 Add 函数,可以分别实现整型、双精度浮点型、长整型的加法,且都是用一个函数名,而在C语言中只能通过定义几个不同名的函数实现。

需要注意,

  1. 函数构不构成重载只与参数有关,与返回值的类型无关:

    【C++】缺省参数 函数重载 内联函数_第2张图片

  2. 对于同样参数类型的传值和传引用也是不构成重载的:

    【C++】缺省参数 函数重载 内联函数_第3张图片

  3. 同类型参数缺省也不能构成函数重载

    【C++】缺省参数 函数重载 内联函数_第4张图片


名字修饰——C++为什么支持函数重载

在C/C++中,一个程序要运行起来,需要经历以下几个阶段:预处理、编译、汇编、链接

预处理阶段会执行预处理指令、展开头文件和替换宏,生成 .i 文件;

编译阶段会进行语法分析、词法分析、语义分析、符号汇总,生成 .s 文件,所以代码中的一些语法错误是在这个阶段发现的;

汇编阶段会生成符号表,将汇编指令转化为二进制指令,生成可重定位目标文件.o

链接阶段会合并段表、合并符号表以及重定位符号表,最终生成 .exe 可执行程序。

实际项目中我们会一些变量和函数声明放在头文件中,函数定义放在 .cpp 文件中,假如一个函数 Fun 定义在了 a.cpp 中,在 b.cpp 中去调用它,那么在汇编阶段会生成符号表,两个文件的符号表中都会有 Fun 函数,但只有 a.o 文件中存有 Fun 函数的地址,那么在链接阶段链接器看到 b.o 调用 Fun ,但没有 Fun 的地址,就会到 a.o 的符号表中去找 Fun 的地址,然后链接到一起。

那么问题来了,如果汇编阶段直接以函数名作为 Fun 函数的符号,那么当对 Fun 函数进行重载时符号表中就会有多个 Fun ,导致链接出问题。

所以就有了名字修饰。

由于 WindowsVS 的修饰规则过于复杂,而 Linuxgcc 的修饰规则简单易懂,所以下面找了一张 gcc 演示图片:

【C++】缺省参数 函数重载 内联函数_第5张图片

可见,在 linux 下,采用 g++ 编译完成后,函数名字的修饰发生改变,编译器将函数参数类型信息添加到修改后的名字中

而C语言是没有这样的名字修饰的,所以C语言也就不支持函数重载。

此外,无论是 Linux 还是 Windows ,函数名字修饰规则都只与函数参数有关,所以这也是为什么函数重载只与参数有关,与返回类型无关。


extern “C”

C++的编译器是兼容C语言的,有些极少见的场景下可能需要C和C++混合编程。

例如:

//test.c
int Add(int a, int b) {
	return a + b;
}

//main.cpp
extern int Add(int a, int b);
int main() {
	Add(1, 2);
	return 0;
}

image-20220810210237460

很显然因为C++的名字修饰,程序发生了链接错误。

解决该问题的方法就是使用extern “C”

//test.c
int Add(int a, int b) {
	return a + b;
}

//main.cpp
extern "C" int Add(int a, int b);
int main() {
	Add(1, 2);
	return 0;
}

extern "C" 的作用就是告诉C++编译器,将指定的函数用C语言的规则去编译,相应的,对应的函数失去了名字修饰,也就无法重载了,其他的倒是没影响。


内联函数

概念

有些简单的函数可能会频繁调用,每次调用函数都会开辟栈帧,这无疑增加了性能开销。

C++推出了一个名为 inline 的关键字。

inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,以此提升程序运行的效率。

【C++】缺省参数 函数重载 内联函数_第6张图片


特性

  1. inline是一种以空间换时间的做法,省去调用函数额开销。所以代码很长或者有循环/递归的函数不适宜使用作为内联函数;
  2. inline对于编译器而言只是一个建议,编译器会自动优化,如果定义为inline的函数体内有循环/递归等等,编译器优化时会忽略掉内联;
  3. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

你可能感兴趣的:(C++,c++,开发语言)