关于 inline 函数的分析: *** undefined reference to ***

  1. 如果将函数的实现放在头文件中,那么每一个包含该头文件的cpp文件都将得到一份关于该函数的定义,那么链接器会报函数重定义错误。
  2. 如果将函数的实现放在头文件,并且标记为 inline 那么每一个包含该头文件的cpp文件都将得到一份关于该函数的定义,并且链接器不会报错
  3. 如果将函数的实现放在cpp文件中,并且没有标记为inline,那么该函数可以被连接到其他编译单元中。
  4. 如果将函数的实现放在cpp文件中,并且标记为inline, 那么该函数对其他编译单元不可见(类似static的效果),也就是其他cpp文件不能链接该函数库,这就是标题中出现的 … undefined reference to …
    问题原因就是,编译器在编译一个inline函数时,需要知道其完整定义,如果编译器在本编译单元找不到inline函数定义就会报错(inline函数的调用不涉及到函数的call,也就不需要链接器参与进来工作,所以也就不会去其他编译单元查找函数定义)。

所以,将类的成员函数的实现放在头文件中不会出现重定义错误,是因为在类中定义成员函数默认为inline函数。

所以下面会报重定义错误(当头文件被两个及以上的cpp文件包含时):

# foo.hpp
class Foo
{
    Foo();
};
Foo::Foo()  // 实现在头文件中,并且没标记为inline,会报编译错误!
{
}

但是如下这样就不会报错:

# foo.hpp
class Foo
{
    Foo()  // 默认 inline
    {}
};

或者如下这样也不会报错:

# foo.hpp
class Foo
{
    inline Foo();
};
Foo::Foo()  // 实现在头文件中,并且显示标记为inline
{
}

如果debug的时候,发现自己明明定义了该函数,却还是报 *** undefined reference to *** 错误,那么可以看一下是不是不小心把cpp文件中的函数写成inline了。

不过,将 inline 函数定义在 cpp 文件中有个好处,正如 《大规模c++程序设计》一书中所说,那就是他拥有 internal linkage 属性(不会输出符号到.o文件中),不会污染全局命名空间(类似static函数):

// file1.cpp
int i                                          // external linkage
int max(int a, int b) {return a > b ? a : b;}  // external linkage
// file2.cpp
inline int min(int a, int b) {return a < b ? a : b;}       // internal
static int fact(int n) {return n<-1 ? 1 : n * fact(n-1);}  // internal

其他同样不会输出符号到.o文件中的有:

// file3.cpp
class Link;  // 类声明
enum { START_SIZE = 1, GROW_FACTOR = 2};  // 枚举定义
const double PI = 3.1415926595;
static Link *s_root_p;
Link * const s_first_p = s_root_p;
typedef int (PointerToFunc *) ();
#define CASE(x) case X: cout << "x" << endl;

参考 see link: https://stackoverflow.com/questions/34208154/inline-functions-in-cpp-files-of-shared-libraries

猜你喜欢

转载自blog.csdn.net/gw569453350game/article/details/77934568