在改动源文件之后,源文件只需要单独编译并链接。而在改动头文件之后,直接或者间接引用头文件的源文件都需要重新编译并链接,这是文件间的编译依存性。
降低编译依存性之构想:相依于声明式,不相依于定义式。
声明式与定义式
定义一种类型的指针或者引用,只需要此类型的声明式,而定义一种类型的实例,则需要此类型的定义式。
声明函数只需要前置声明参数和返回值的类型,并不需要提前定义类型。而定义函数或者调用函数,必须先引入参数与返回值的类型定义式。
接口与实现分离
编译依存性最小化的本质是接口与实现分离,其关键在于以声明依存性替换定义依存性。
尽量在头文件使用声明式,而定义式放至源文件。接口与实现解除耦合,头文件之间减少引用,从而降低文件间的编译依存性。
实现细节隐藏技巧
抽象类之数据结构,封装结构体,声明于头文件,而定义于源文件。结构体限定为类的私有类型,以增强类的封装性,不仅避免污染类外名称空间,而且使数据结构透明化,即类的使用者不必知悉数据结构。
内联局限性
接口与实现分离用于隐藏实现细节,而内联的前提是显示实现细节,二者相互矛盾。
正所谓有得必有失,关键在于如何取舍。
对于自定义结构,头文件倘若只有声明式而无定义式,则无法访问结构数据。换句话说,采用实现细节隐藏技巧,意味着仅限定义式所在源文件定义与调用内联函数。
编译器优化策略可以无视内联局限性,即使头文件只有函数声明式而无无定义式,直接或者间接引用头文件而无定义式的源文件也可以内联函数。
参考资料
[1] Effective C++ 中文版:改善程序与设计的55个具体做法(第3版)/ [美]Scott Meyers著;侯捷译. --北京:电子工业出版社,2011.1