2011-06-03 91 views
7

所以有一天,我正在浏览一些旧的C++书籍,并注意到创建一个我从未见过的C++类的方法。到目前为止,我所见过的所有东西都使用#include“header.h”,并分别编译实现文件。我看到这本书的作者所做的实际上是在头文件末尾的实现中加入一个包含指令,并从编译中省略.cpp文件。有人使用过这种风格吗?C++ #include风格差异

例如: 我 的main.cpp employee.h employee.cpp

//main.cpp 
#include <iostream> 
#include <stdio.h> 
#include <string> 
#include "employee.h" 
void main() 
{/*some code*/} 

//employee.h 
#ifndef EMPLOYEE_H 
#define EMPLOYEE_H 
class employee 
{ 
    public: 
    //public members 
    private: 
    //private members 
} 
#endif 

//employee.cpp 
#include "employee.h" 
#include <string> 
//public member definitions 

我会normaly编译这个项目像这样:

g++ main.cpp employee.cpp 

但在笔者的例子是这样的

//main.cpp 
#include <iostream> 
#include <stdio.h> 
#include <string> 
#include "employee.h" 
void main() 
{/*some code*/} 

//employee.h 
#ifndef EMPLOYEE_H 
#define EMPLOYEE_H 
class employee 
{ 
    public: 
    //public members 
    private: 
    //private members 
} 
#include "employee.cpp" // <-- the line of code that caught my attention 
#endif 

//employee.cpp 
#include <string> 
//public member definitions 

而产生的代码编译为

g++ main.cpp 

这仅仅是一种风格偏好还是有这个任何真正的实惠?我认为它不会很好地扩展,但我不是一个超级熟练的C++程序员。

+3

这是哪本书? – 2011-06-03 16:24:45

+4

是的,我也想避免那本书。 – Beta 2011-06-03 16:27:14

+0

@Neil“C++类和数据结构”Jeffrey S. Childs ISBN 0-13-158051-5 978-0-13-1558051-0。其实它并没有那么古老,这本书拥有2008 – 2011-06-03 16:27:57

回答

3

这样做会带来类的定义,每一个翻译单元,其中头文件包括在内。这是一个非常不寻常的范例,可能会危害您的编码健康。特别是,如果你有main.cppfoo.cpp这两者都是#include "employee.h",那么employee上的所有方法都会被定义两次,这是违反了One Definition Rule并且会产生连接错误。为了解决这些链接器错误,你需要将定义移动到他们自己的翻译单元,或者将它们标记为inline(这可能会也可能不起作用)。

然而这在某些情况下是有用的习惯用法。特别是使用必须在翻译单元内定义的模板。在这种情况下,如果您希望在单独的文件中进行声明和实现以提高可读性,则可以执行文件结尾#include。当我这样做时,我使用了一个特殊的文件扩展名.hpp来表示该文件是特殊的,因为它并不打算自行编译。一个例子见this answer

+1

@Richard:ODR也是关于单独翻译单元中的多个定义,并且包括警卫不会阻止这种情况发生。如果标题包含非内联函数定义并且它包含在多个翻译单元中,那么您将收到链接错误。 @John:声明函数'inline' *将*修正链接器错误 - 这正是'inline'的用途。 – 2011-06-03 21:43:14

+0

@Mike:Doh - 脑冻结....当然你是对的! - 我删除了令人尴尬的评论! – 2011-06-08 12:51:18

2

这可能不是主流的书。无论如何,如果我们通过“编译”的条件来定义正确性,那么是的,这是一个风格问题,两种风格都是正确的。

但是,根据与其他编程语言相匹配的标准和设计准则,唯一真正正确的样式是第一个,它符合单独编译翻译单元的精神。正如你自己所说的,第二种风格不会很好地扩展。

还有一点是注意#include < stdio.h中>,这不是标准的任何更多:

#include <cstdio> 
2

这肯定会工作,但它有两个缺点:

  • 编译时间越来越长 - 通常,如果你改变一个文件,你只需要编写一个文件,链接器将其与结合其他较旧的编译结果。当所有内容都包含在单个文件中时,所有内容都需要立即重新编译。
  • 潜在的命名空间冲突 - 在一个模块中声明的任何符号现在都可以看到它们。如果您使用任何宏,这可能是一个大问题。
3

该方法有时在提供模板时使用,等同于在头文件中提供模板和实现,但是允许人们在不通过代码的情况下读取模板声明。等价地,如果您提供了d函数,如果您也这样做了,这将是可以理解的(不会达到建议的程度,但可以理解)。

对于其他任何东西,这是一个坏方法。它不仅要求所有翻译单元实际编译所有函数定义,还需要声明所有函数为inline,或者包含来自单个翻译的标题,否则会触发链接器错误。

0

这实际上是我在构建系统中看到的一个技巧,每晚构建系统以加速它们,包括所有cpp文件,并且它们编译时可以在总体速度上产生一些重大收益。