跳转至

Functions⚓︎

782 个字 43 行代码 预计阅读时间 4 分钟

Overloaded Functions⚓︎

构造函数的名称与类名相同。有时我们需要一个默认的构造函数,但是有时也需要另一个带参数的构造函数,这两件事是可以同时做到的——利用函数重载(function overloading),相同的函数可以接受不同的参数列表,也能做到自动类型转换:

void print(char * str, int width); // #1
void print(double d, int width); // #2
void print(long l, int width); // #3
void print(int i, int width); // #4
void print(char *str); // #5
print("Pancakes", 15);
print("Syrup");
print(1999.0, 10);
print(1999, 12);
print(1999L, 15);

void f(short i);
void f(double d);
f('a');
f(2);
f(2L);
f(3.2);

分派构造函数 (delegating ctor)

  • 在很多构造函数中重复初始化代码是一种不良设计——代码重复(code duplication)
  • 解决方案是使用私有的构造函数为其他成员进行初始化
  • 可以实现一串分派构造函数
例子
class class_c {
public:
    int max;
    int min;
    int middle;
    class_c(int my_max) {
        max = my_max > 0 ? my_max : 10;
    }
    class_c(int my_max, int my_min) : class_c(my_max) {
        min = my_min > 0 && my_min < max ? my_min : 1;
    }
    class_c(int my_max, int my_min, int my_middle) : class_c (my_max, my_min) {
        middle = my_middle < max && my_middle > min ? my_middle : 5;
    } 
};
int main() {
    class_c c1{ 1, 3, 2 };
}

Default Arguments⚓︎

默认参数(default arguments) 是在声明的时候给予的值,如果在函数调用中没有为该参数提供值,那么编译器会自动插入默认值。

int harpo(int n, int m = 4, int j = 5);
int chico(int n, int m = 6, int j);//illeagle
int groucho(int k = 1, int m = 2, int n = 3);
beeps = harpo(2);
beeps = harpo(1,8);
beeps = harpo(8,7,6);

定义函数的参数列表时,默认值必须自右向左添加。

陷阱

默认参数仅在原型中声明,并没有在函数头中定义 ❌

Inline Functions⚓︎

函数调用的开销:设备所需的处理时间先于命令的执行

  • 压入参数
  • 压入返回地址
  • ...
  • 准备返回值
  • 弹出之前压入的所有内容

学过计组的话对这部分应该比较熟悉。

内联函数(inline function) 直接在代码中展开,就像预处理器宏一样,所以函数调用的开销就少了很多。

inline int plusOne(int x);
inline int plusOne(int x) { return ++x; };
  • 声明和定义内联函数的时候都要指出 inline 关键字
  • 内联函数定义可能不会在 .obj 文件中生成任何代码

在头文件的内联函数

  • 因此可以将内联函数体放在头文件中,然后在用到它的时候使用 #include
  • 不要害怕使用多定义的内联函数。内联函数的定义本质上就是声明,因为它们没有主体

内联函数的权衡

  • 被调用的函数主体会被插入到调用者中
  • 这可能会增大代码体积,但是减少了调用开销,所以是以空间换时间。在大多数情况下,这样做是值得的
  • 它比 C 的宏更好,因为能够检查参数类型

内联函数可能不是在行内的 (in-line)。因为编译器并不看重把。它可能认为函数太大了,或者注意到它调用自身(内联函数不允许或不可能使用递归,或者编译器可能没有实现内联函数的功能。

任何定义在类声明的函数都会被自动视为内联函数。

陷阱

  • 可以将内联成员函数的定义放在类定义之外,但此时函数的定义需要放在它们被调用之前的位置,比如放在头文件里

降低聚集

何时使用内联函数?

  • 适用场景:2-3 行、频繁调用的函数
  • 不太适用的地方:非常大的函数(超过 20 、递归函数
  • 偷懒的方法:要么一直用内联函数,要么一直不用

评论区

如果大家有什么问题或想法,欢迎在下方留言~