繁体   English   中英

在头文件与实现(.cpp)文件中定义构造函数

[英]Defining constructor in header file vs. implementation (.cpp) file

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

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

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

你对此有何看法?

保持标头不受实现的影响,除非您希望实现内联(例如,琐碎的getter / setter)。 当然,除非他们是模板。

我认为没有理由为构造函数做一个例外。 将它们放在.cpp文件中。

需要注意的一点是,如果在头文件中定义了成员函数,它必须位于类体内,或者必须明确标记为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,即使使用它们也最好小心 - 有一天它们可能变得非常重要,这将意味着大量的重新编译和兼容性破坏。

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM