【问题标题】:Defining constructor in header file vs. implementation (.cpp) file在头文件与实现 (.cpp) 文件中定义构造函数
【发布时间】:2011-01-21 17:26:13
【问题描述】:

我可以在类.h 文件或实现文件.cpp 中定义类构造函数的主体。就特定项目中的编译器而言,这两种风格可能是相同的(对我来说,项目意味着 DLL)。 这同样适用于任何成员函数:它们可以在头文件中定义,也可以在头文件中声明,然后在 cpp 文件中定义。

但是,我发现如果我需要在不同的项目中包含这样的类头文件(这意味着最终使用头文件的代码最终会出现在不同的 DLL 中)然后有头文件中的实际实现在编译时会引起一些麻烦(而不是在链接时......我什至没有达到这一点)。 为什么?好吧,我不会详细说明,但编译器显然会尝试解析可能在其他头文件等中定义的所有函数,从而迫使可怜的开发人员开始拉入各种头文件等。

保持头文件没有任何实现并仅将它们用于“声明”不是总是最好的吗?这将使它们更容易包含在多个项目中,而不必携带大量额外的垃圾。

您对此有何看法?

【问题讨论】:

    标签: c++ constructor header-files


    【解决方案1】:

    需要注意的重要一点是,如果在头文件中定义了成员函数,则它必须在类主体中,或者必须显式标记为inline。换句话说,在头文件中这样做是完全错误的:

    class A {
      public:
        A();
    };
    
    A::A() {
      // constructor body
    }
    

    它错的原因是因为它会使编译器在每个编译单元中包含定义,而很明显任何函数必须只定义一次。以下是做同样事情的正确方法:

    class A {
      public:
        inline A();
    };
    
    inline A::A() {
      // constructor body
    }
    

    或者:

    class A {
      public:
        inline A() { // inline isn't required here, but it's a good style
         // constructor body
        }
    };
    

    在这两种情况下,构造函数都是内联的。使其成为常规外联函数的唯一正确方法是在实现文件中定义它,而不是在头文件中。这是这两种方法之间最重要的区别。

    现在,值得注意的是内联是一种优化。与优化一样,在证明有必要之前最好避免使用它们。在内联可能导致的其他问题中,还有兼容性问题:如果您更改了未内联的函数的主体,您只需重新编译定义它的单元,每个人都立即开始使用新的实现。使用内联函数,您需要重新编译包含相关标头的每个单元,这可能会很痛苦,尤其是当标头由不同的人在不同项目中使用时。

    换句话说,尽可能使用常规的外联定义,直到通过分析证明特定函数调用是性能瓶颈。这条规则唯一合理的例外是琐碎的 setter 和 getter,即使使用它们也最好小心 - 有一天它们可能会变得不平凡,这将意味着大量的重新编译和兼容性破坏。

    【讨论】:

      【解决方案2】:

      保持您的标头没有实现,除非您希望内联实现(例如琐碎的 getter/setter)。当然,除非它们是模板。

      我认为没有理由对构造函数进行例外处理。将它们放在 .cpp 文件中。

      【讨论】:

      • 在某些情况下,您可以将实现放在标题中。比如说,如果两个不同的文件都需要相互包含,那不能在 header 中完成,必须在 cpp 中完成。
      • “平凡”异常可以很容易地应用于平凡的构造函数。没有理由区别对待它们或不将它们内联。
      • 请注意,显式默认的 ctor/dtor/op= 只有在课堂上实现时才可能是微不足道的。
      【解决方案3】:

      需要考虑的另一个注意事项:对头文件的任何更改都需要重新构建包含该头文件的所有文件。大多数构建系统将重建依赖于修改后的头文件的源 (*.cpp/.cc) 文件。

      如果更改头文件中定义的类的方法,则包括头文件在内的所有源文件都将被重建。如果您更改源文件中的方法,则仅重建源文件。这可能是大中型项目的问题。

      为了简化构建过程,类的大多数方法都应该在源文件中定义。小方法和其他内联候选应该在头文件中定义。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-21
        • 1970-01-01
        • 1970-01-01
        • 2022-12-21
        • 2016-02-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多