上篇文章说过,有四种情况可以在头文件中定义: 1. 内联函数的定义 2. 类定义 3. const和static变量 4. 模板函数/类
inline函数(即内联函数)对编译器而言必须是可见的,以便能够在调用点展开该函数,与非inline函数不同的是,inline函数必须在调用该函数的每个文件中定义。当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同。
正因为如此,建议把inline函数的定义放到头文件中,在每个调用该inline函数的文件中包含该头文件。这种方法保证了每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命周期中引起无意的不匹配的事情。——摘自《C++ Primer》(第三版)
因为在程序中创建一个类的对象时,编译器只有在这个类的定义完全可见的情况下,才能知道这个类的对象应该如何布局,所以,关于类的定义的要求,跟内联函数是基本一样的。所以把类的定义放进头文件,在使用到这个类的.cpp文件中去包含这个头文件,是一个很好的做法。在这里,值得一提的是,类的定义中包含着数据成员和函数成员。数据成员是要等到具体的对象被创建时才会被定义(分配空间),但函数成员却是需要在一开始就被定义的,这也就是我们通常所说的类的实现。
const 和 static 变量,可以放在头文件中 const对象默认是static的,而不是extern的,所以即使放在头文件中声明和定义。多个cpp引用同一个头文件,互相也没有感知,所以不会导致重复定义。但是const/static变量放在头文件定义,每个cpp文件包含该头文件会导致有多个该const/static变量,虽然它们互不感知,但是会造成空间的浪费,所以不要直接在头文件中定义const或static变量,更好的写法是在源文件中定义,在头文件中extern声明。
模板函数/类并不是一定要放在头文件中,放在其他文件,编译也能通过,因为.h文件中有模板的声明, 但是链接的时候,需要实例化模板,这时候就需要找模板的具体实现了。但是.h文件中只包含模板的声明,不包含模板的具体实现,这时候就会出现链接错误,而模板的实现.cpp里面,虽然有模板的具体实现,但是没有谁在该.cpp里面使用一个模板函数,就不会生成一个具体化的实例,所以推荐模板的声明与定义都放在.h文件中