如何在头文件中添加函数定义?
有三种可能的方法:
1. 将函数标记为`inline`
2. 将函数声明为`static`
3. 将函数放在匿名命名空间中
那么正确的做法是什么呢?
方法一即将函数标记为`inline`,这是不破坏“单一定义规则”的正确方式。
其他两种方法有什么问题?
在第二种和第三种方法中,每个翻译单元将包含其自己版本的函数。因此,程序将包含多个不同版本的函数,从而导致生成的二进制文件大小增加。
对于一个`static`函数fun(),每个翻译单元中的`&fun`都是不同的,程序将包含N个不同版本的函数。此外,如果函数包含静态局部变量,则将有N个不同的静态局部变量,每个函数实例一个。
第一种方法如何避免这个问题?
内联函数具有外部链接性。当将函数标记为`inline`时,在所有翻译单元中该函数将具有相同的地址。此外,在内联函数体内定义的静态局部变量和字符串字面量在翻译单元之间被视为同一对象。简而言之,内联函数在所有翻译单元中具有相同的地址。
那么,在头文件中使用`static inline`函数定义有什么意义呢?
static
关键字强制函数具有内部链接。作为内联定义的函数的每个实例都被视为一个单独的函数,并且每个实例都有自己的静态局部变量和字符串字面量的副本。因此,这类似于
#2
。
需要注意的是,标准规定在用户程序中所有的
inline
函数定义必须在使用或调用该函数的所有翻译单元中具有完全相同的定义。
相关标准文献引用:
C++03标准
3.2 One definition rule:
Para 3: 每个程序必须包含每个非内联函数或对象的确切定义,该程序中使用该函数或对象;不需要诊断。该定义可以显式地出现在程序中,可以在标准库或用户定义的库中找到,或者(适当时)是隐式定义的(请参见12.1、12.4和12.8)。内联函数必须在使用它的每个翻译单元中定义。
7.1.2 Function specifiers
Para 4: 内联函数必须在使用它的每个翻译单元中定义,并且在每种情况下都必须具有完全相同的定义(3.2)。[注意:可以在翻译单元中出现内联函数的调用,而其定义尚未出现。]如果在一个翻译单元中声明了具有外部链接的内联函数,则必须在所有出现的翻译单元中声明具有内联函数;不需要诊断。具有外部链接的内联函数在所有翻译单元中都应具有相同的地址。extern inline函数中的静态局部变量始终引用同一对象。在extern inline函数中的字符串字面值是不同翻译单元中的同一对象。