[英]Inline functions in multiple translation units
让我们从以下C ++文件集开始:
// my_class.h
struct MyClass
{
void my_func();
};
void MyClass::my_func()
{}
// f.h
void f1();
void f2();
// f1.cpp
#include "my_class.h"
void f1()
{
MyClass a;
a.my_func();
}
// f2.cpp
#include "my_class.h"
void f2()
{
MyClass a;
a.my_func();
}
// main.cpp
#include "f.h"
int main()
{
f1();
f2();
return 0;
}
我试着用这个代码编译
$ g++ f1.cpp f2.cpp main.cpp
显然,链接器抱怨重复的符号my_func
:
duplicate symbol __ZN7MyClass7my_funcEv in:
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f1-962ae7.o
/var/folders/yj/zz96q16j6vd1dq1_r3mz8hzh0000gn/T/f2-aef78c.o
ld: 1 duplicate symbol for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我的下一次尝试是在类定义中移动函数定义,因此我们得到:
struct MyClass
{
void my_func()
{}
};
运行相同的g++
命令,程序成功编译。 这是因为类定义中定义的函数是inline
隐式标记的(第10.1.6节* 3)。
标准规定:
带有内联说明符的函数声明(11.3.5,12.2.1,14.3)声明了一个内联函数。 内联说明符向实现指示在调用点处函数体的内联替换优先于通常的函数调用机制。 在呼叫点执行此内联替换不需要实现; 但是,即使省略了这种内联替换,仍应遵守本节中规定的内联函数的其他规则
这似乎与cppreference.com上的内容相矛盾:
因为函数内联关键字的含义意味着“允许多个定义”而不是“内联是首选”,[...]
因此,据我所知,在类定义中定义的函数使其隐式inline
,这并不一定意味着编译器将选择内联其主体,而是在每个转换单元中定义它。 它是否正确?
关于模板类的第二个问题。 分离模板类的声明/定义是一个问题,如此处所述,因此我们只能在类定义中使用函数定义,使其隐式inline
,再次,对吗? 这有什么影响?
因为当类是模板时,我们只能选择在类定义中定义函数,所以对于不是模板的类,要做什么? 我们应该在源文件中定义函数,只在可能的情况下将声明保留在头文件中吗?
因此,据我所知,在类定义中定义的函数使其隐式
inline
,这并不一定意味着编译器将选择内联其主体,而是在每个转换单元中定义它。 它是否正确?
正确。 当在类中定义时,它被标记为内联,并且可以将该defenition带入多个翻译单元。 编译器将为您处理。
关于模板类的第二个问题。 分离模板类的声明/定义是一个问题,如此处所述,因此我们只能在类定义中使用函数定义,使其隐式
inline
,再次,对吗? 这有什么影响?
这是不正确的。 模板很特别。 它们实际上并不是编译代码后会存在的任何东西。 什么是模板,是用于标记类或函数的方法。 因此, 它们也隐式内联 ,允许模板包含在使用它的每个转换单元中,因此编译器可以根据需要从中删除具体的类/函数。 这意味着您可以在类之外定义类成员函数。
因为当类是模板时,我们只能选择在类定义中定义函数,所以对于不是模板的类,要做什么? 我们应该在源文件中定义函数,只在可能的情况下将声明保留在头文件中吗?
通常,您希望将定义放在cpp文件中。 您从中获得的好处是,如果更改了函数的实现,则只需要重新编译一个cpp文件。 如果它们在头文件中,那么您需要重新编译包含该头文件的每个cpp文件,这会导致更长的构建时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.