【问题标题】:c++ #include style differencesc++ #include 风格差异
【发布时间】:2011-06-03 16:23:30
【问题描述】:

所以前几天,我翻阅了一些旧的 C++ 书籍,发现了一种创建 C++ 类的方法,这是我以前从未见过的。到目前为止,我所看到的所有内容都始终使用#include“header.h”并单独编译实现文件。我看到这本书的作者所做的实际上是在头文件的末尾为实现添加了一个包含指令,并从编译中省略了 .cpp 文件。有人用过这种风格吗?

例如: 我有 主文件 雇员.h 员工.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

我通常会像这样编译这个项目:

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++ 程序员。

【问题讨论】:

  • 是的,我也想避开那本书。
  • @Neil “C++ 类和数据结构”作者 Jeffrey S. Childs ISBN 0-13-158051-5 978-0-13-1558051-0。其实没那么老,这本书有2008年的版权
  • @Matt,这不会是一个问题,因为有包括警卫,但这肯定不是推荐的方法。
  • @Beta 我会说它更强一些。从那本书中逃跑!!!看来这本书在amazon 的评分略高于 2 星,主要是因为糟糕的例子。
  • +1 告诉我要避免哪本书。 :)

标签: c++ coding-style include


【解决方案1】:

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

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

【讨论】:

  • @Richard:ODR 也是关于在单独的翻译单元中的多个定义,并且包含守卫不会阻止这种情况。如果标题包含非内联函数定义并且它包含在多个翻译单元中,那么您将收到链接错误。 @John:声明函数inline 修复链接器错误——这正是inline 的用途。
  • @Mike:Doh - 大脑冻结......是的,你当然是对的! - 我已经删除了尴尬的评论!
【解决方案2】:

这种方法有时在提供模板时使用,相当于在头文件中提供模板和实现,但允许人们阅读模板声明而无需查看代码。等效地,如果您提供 inlined 函数,那么如果您提供相同的功能,那将是可以理解的(虽然没有达到推荐的程度,但可以理解)。

对于其他任何事情,这是一个糟糕的方法。它不仅要求所有翻译单元实际编译所有函数定义,还要求您将所有函数声明为inline,或包含单个翻译的标头,否则会触发链接器错误。

【讨论】:

    【解决方案3】:

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

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

    另一点是#include ,它不再是标准的:

    #include <cstdio>
    

    【讨论】:

      【解决方案4】:

      这肯定行得通,但它有几个缺点:

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

      【讨论】:

        【解决方案5】:

        这实际上是我在构建系统中看到的一个技巧,夜间构建可以加快它们的速度,包括所有 cpp 文件,并且编译它可以大大提高整体速度。

        【讨论】:

          猜你喜欢
          • 2016-06-05
          • 2013-07-07
          • 2010-12-08
          • 2010-09-30
          • 1970-01-01
          • 1970-01-01
          • 2010-11-08
          • 2020-03-17
          • 1970-01-01
          相关资源
          最近更新 更多