Loading

欢乐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++ 为这个功能提供几个解决方法:

  1. initializer_list 模板类。它用于处理参数类型已知,参数个数不确定的情况。

    其保存的元素是实参的拷贝,并且其元素不可修改,只能用迭代器进行遍历。

    但可以通过保存指针或迭代器而间接修改实参。

  2. 可变参数模板,可以用来处理参数类型未知,参数个数未知的情况。

    见模板一章

  3. 省略符形参。其实际上C 的功能,C++保留了这一特性。

    C 语言中的printf 实际上就是这种格式。处理起来较为麻烦。

constexpr 函数

为了能在编译过程随时展开,constexpr 函数其实也是隐式内联

constexpr 函数不一定返回常量表达式。

posted @ 2020-01-02 10:09  沉云  阅读(104)  评论(0编辑  收藏  举报