欢乐C++ —— 4. 函数
返回类型
如果是返回 值的形式,那么编译器会创建临时对象,并利用返回值来初始化这个对象。
但如果是类类型的话有时会优化掉这个临时对象。
尾置返回类型:将返回类型放到形参后面,这样对于返回复杂类型来说看上去更清晰。
例如 auto fun()->int;
声明函数 fun 不接受参数,并且返回 int
从C++14开始,可以自动推断返回类型即这样声明:
auto fun();
返回多个值:当想使函数返回多个值,虽然可以定义一个数据结构,但是有一个小技巧是利用传引用给函数,然后在函数内修改。
参数默认值
使用默认值和使用常量调用效果是一样的,都是直接把相应的值直接push到栈中,一般的push顺序是从右往左,而使用变量的话会先从内存中取值到eax寄存器,然后再压入栈中。
int sum(int a=10, int b=20)
{
int temp;
temp = a + b;
return temp;
}
/*
栈 栈顶esp寄存器栈顶地址 栈底ebp寄存器栈底地址
*/
int main()
{
int a = 10; // mov dword ptr[ebp-4], 0Ah
int b = 20; // mov dword ptr[ebp-8], 14h
/*
mov eax, dword ptr[ebp-8]
push eax
mov eax, dword ptr[ebp-4]
push eax
*/
int ret = sum(a, b); // #1
cout << "ret:" << ret << endl; // << endl << '\n';
ret = sum(10); // #2
/*
push 14h
push 0Ah
call sum
*/
ret = sum(); // #3
/*
push 14h
push 0Ah
call sum...
*/
ret = sum(10, 20); // #4
sum(a);
return 0;
}
内联函数
内联函数是指在 release 版本 在编译阶段把函数的代码插入函数调用处,所以内联函数的调用没有标准的函数调用开销。
-
在 debug 版本,内联函数不起作用,所以像普通函数一样可以调试。
-
内联函数不会产生意外参数问题,相比较宏,安全性更高。
-
内联只是一种给编译器的建议。
-
一般来说函数的调用开销比执行开销大时,声明成内联。
-
c99版本也支持内联函数。
函数重载
函数名相同,但是参数列表不同的一组函数称作函数重载,和函数的返回值类型没有任何关系。
-
c++ 支持函数重载的基础是c++ 编译器生成符号的规则不同。相比较与c语言,c++编译器产生函数符号是根据函数名+参数列表生成的。
-
顶层const 不支持重载, 因为在传参上没有限制。
//顶层const int *const p; int &const p; const int n; //底层const const int *p; const int &p;
-
决定好要调用哪个重载函数是在编译期间决定好的。
-
main 函数不支持重载。
-
为了在c++中能够使用由c语言编写的函数,可以使用如下语法使c++编译器按照c语言规则生成函数符号。在有的头文件函数声明会这样写。
#ifdef __cplusplus extern "C" { #endif int sum(int, int); #ifdef __cplusplus } #endif
-
其它的重载
-
类成员函数中,this 指针的 const 重载
-
类成员函数中,左右值版本的重载
-
同一个函数模板中实例化生成的模板函数之间也算重载。
-
内联函数
内联函数是指在 release 版本 在编译阶段把函数的代码插入函数调用处,所以内联函数的调用没有标准的函数调用开销。
- 在 debug 版本,内联函数不起作用,所以像普通函数一样可以调试。
- 内联函数不会产生意外参数问题,相比较宏,安全性更高。
- 内联只是一种给编译器的建议。
- 一般来说函数的调用开销比执行开销大时,声明成内联。
- c99版本也支持内联函数。
现代C++ 除了assert 之外很少再使用预处理宏
可变形参
有时,我们的函数需要处理预先不知道形参个数的情况。C++ 为这个功能提供几个解决方法:
-
initializer_list 模板类。它用于处理参数类型已知,参数个数不确定的情况。
其保存的元素是实参的拷贝,并且其元素不可修改,只能用迭代器进行遍历。
但可以通过保存指针或迭代器而间接修改实参。
-
可变参数模板,可以用来处理参数类型未知,参数个数未知的情况。
见模板一章
-
省略符形参。其实际上C 的功能,C++保留了这一特性。
C 语言中的printf 实际上就是这种格式。处理起来较为麻烦。
constexpr 函数
为了能在编译过程随时展开,constexpr 函数其实也是隐式内联
constexpr 函数不一定返回常量表达式。