1 、引子
在平常的 C/C++(www.cppentry.com) 开发中,几乎所有的人都已经习惯了把类和函数分离放置,一个 .h 的头文件里放声明,对应的 .c 或者 .cpp 中放实现.从开始接触,到熟练使用,几乎已经形成了下意识的流程.尽管这样的做法无可厚非,而且在不少情况下是相对合理甚至必须的,但我还是要给大家介绍一下把实现全部放置到头文件中的方式,给出可供大家使用的另一个选择.同时针对这一做法,也顺便说一下其优缺点以及需要注意的情况.
我是一个很喜欢简洁的人,多年以来甚至养成了这样的癖好,如果一个功能是能够用一条语句实现的,那就不要用两条语句.在我看来,如果给别人提供一份可以复用的代码的话,最优雅的状态莫过于仅仅提供一个头文件就全部搞定.之所以不太喜欢引入源文件,最重要的原因是源文件往往会带来工程文件的变化;而且,在使用过程中也会增加一些额外的操作,例如,在一个组织良好的工程里,头文件和源文件很有可能是位于不同的目录,这样就会多带来一次文件复制操作.
2 、正文
2.1 顾虑
我遇到有不少人不使用头文件来包含实现,往往是出于以下几种顾虑:
1、 暴露了实现细节
2、 头文件被包含到不同的源文件中,会导致链接冲突
3、 头文件被包含到不同的源文件中,会导致有多份实现被编译出来,增大可执行体的体积
如果有顾虑 1 ,那很显然应该在第一时间抛弃完全在头文件中实现的念头.不过我遇到的情形里,通常后两种顾虑占据了绝对的比例.而这种顾虑,通常是由于对 C/C++(www.cppentry.com) 没有足够的了解导致的.
有顾虑 2 的,经常会是一些有 C 语言开发经验的程序员.他们所担心的也往往是出现的全局函数的情况.例如有以下头文件 c_function.h (清晰起见,防卫宏之类的代码没有列出):
[cpp]
int integer_add(const int a, const int b)
{
return a + b;
}
如果在同一工程中,有 a.c (或者是 .cpp )和 b.c 两个(或两个以上)源文件包含了此头文件,则在链接时期就会发生冲突,因为在两个源文件编译得到的目标文件中都有一份 integer_add 的函数实现,导致链接器不知道对于调用了此函数的调用者,应该使用哪一个副本.