赞成和反对;将所有代码放在C+的头文件中的缺点+;? 你可以构造一个C++程序,这样几乎所有代码都驻留在头文件中。它本质上看起来像一个C#或Java程序。但是,在编译时,至少需要一个.cpp文件才能拉入所有头文件。现在我知道有些人会非常讨厌这个想法。但我还没有发现这样做有任何令人信服的缺点。我可以列举一些优点:

赞成和反对;将所有代码放在C+的头文件中的缺点+;? 你可以构造一个C++程序,这样几乎所有代码都驻留在头文件中。它本质上看起来像一个C#或Java程序。但是,在编译时,至少需要一个.cpp文件才能拉入所有头文件。现在我知道有些人会非常讨厌这个想法。但我还没有发现这样做有任何令人信服的缺点。我可以列举一些优点:,c++,architecture,compilation,header-files,circular-dependency,C++,Architecture,Compilation,Header Files,Circular Dependency,[1] 更快的编译时间。所有头文件只解析一次,因为只有一个.cpp文件。此外,一个头文件不能包含多次,否则您将获得构建中断。在使用替代方法时,还有其他方法可以实现更快的编译,但这非常简单 [2] 它避免了循环依赖,使它们绝对清晰。如果ClassA.h中的ClassA与ClassB.h中的ClassB有循环依赖关系,我必须提出一个参考&它很突出。(请注意,这与C#&Java不同,C#&Java编译器会自动解析循环依赖项。这会鼓励错误的编码实践)。同样,如果您的代码在.cpp文件中,您可以避免循环依

[1] 更快的编译时间。所有头文件只解析一次,因为只有一个.cpp文件。此外,一个头文件不能包含多次,否则您将获得构建中断。在使用替代方法时,还有其他方法可以实现更快的编译,但这非常简单

[2] 它避免了循环依赖,使它们绝对清晰。如果
ClassA.h
中的
ClassA
ClassB.h
中的
ClassB
有循环依赖关系,我必须提出一个参考&它很突出。(请注意,这与C#&Java不同,C#&Java编译器会自动解析循环依赖项。这会鼓励错误的编码实践)。同样,如果您的代码在
.cpp
文件中,您可以避免循环依赖,但在实际项目中,
.cpp
文件往往包含随机标题,直到您无法确定谁依赖于谁为止


您的想法?

对我来说,明显的缺点是您总是必须一次构建所有代码。使用
.cpp
文件,您可以进行单独的编译,因此您只能重建真正发生变化的位。

我不同意第1点

是的,只有一个.cpp,从头开始构建的时间更快。但是,您很少从头开始构建。您需要做一些小的更改,每次都需要重新编译整个项目

我更喜欢用另一种方式:

  • 在.h文件中保留共享声明
  • 在.cpp文件中保留仅在一个位置使用的类的定义
因此,我的一些.cpp文件开始看起来像Java或C#code;)


但是,由于第2点,在设计系统时,“将内容保留在.h”方法是好的。你犯了错误。我通常在构建类层次结构时这样做,稍后当代码体系结构变得稳定时,我会将代码移到.cpp文件中。

静态或全局变量kludges甚至更不透明,可能无法调试。 例如,计算分析的总迭代次数。 在我的乱七八糟的文件中,将这些项目放在cpp文件的顶部使它们很容易找到。
所谓“可能无法调试”,我的意思是,我会定期将这样一个全局设置放入监视窗口。因为它总是在范围内,所以无论程序计数器现在在哪里,监视窗口总是可以到达它。通过将这些变量放在头文件顶部的{}之外,可以让所有下游代码“看到”它们。如果将程序放在{}中,如果程序计数器在{}之外,则调试器将不再将它们视为“作用域”。然而,在Cpp顶部的kludge global中,即使它可能是全局的,以至于显示在您的链接地图pdb等中,如果没有extern语句,其他Cpp文件也无法访问它,从而避免意外耦合。

您误解了该语言的用途。cpp文件实际上是(或者应该是内联代码和模板代码除外)系统中唯一的可执行代码模块。cpp文件被编译成对象文件,然后链接在一起。h文件的存在仅用于转发.cpp文件中实现的代码声明

这会导致更快的编译时间和更小的可执行文件。它看起来也相当干净,因为您可以通过查看类的.h声明快速了解类

至于内联代码和模板代码——因为这两种代码都是由编译器而不是链接器生成代码的——它们必须根据.cpp文件始终对编译器可用。因此,唯一的解决方案是将其包含在.h文件中


然而,我已经开发了一个解决方案,其中我在.h文件中有我的类声明,在.inl文件中有所有模板和内联代码,在.cpp文件中有所有非模板/内联代码的实现。.inl文件包含在my.h文件的底部。这可以保持事情的干净性和一致性。

您可以说您的解决方案是有效的。它甚至可能对您当前的项目和开发环境没有缺点

但是

正如其他人所说,将所有代码放在头文件中,每次更改一行代码时都会强制进行完整编译。这可能还不是一个问题,但您的项目可能会变得足够大,以至于编译时间将成为一个问题

另一个问题是在共享代码时。虽然您可能还没有直接关心,但对代码的潜在用户尽可能多地隐藏代码是很重要的。通过将您的代码放入头文件,任何使用您的代码的程序员都必须查看整个代码,而他们只是对如何使用它感兴趣。将代码放在cpp文件中只允许以头文件的形式交付二进制组件(静态或动态库)及其接口,这在某些环境中可能更简单

如果您希望能够将当前代码转换为动态库,这是一个问题。由于没有与实际代码解耦的适当接口声明,因此无法将编译后的动态库及其使用接口作为可读头文件交付

您可能还没有这些问题,这就是为什么我告诉您,您的解决方案在您当前的环境中可能还可以。但对任何变化做好准备总是更好的,其中一些问题应该得到解决

PS:关于C#或Java,你应该记住这些语言并没有按照你说的做。它们实际上是独立编译文件(如cpp文件)
struct A
{
   B * b ;
   void doSomethingWithB() ;
} ;

struct B
{
   A * a ;
   void doSomethingWithA() ;
} ;

void A::doSomethingWithB() { /* etc. */ }
void B::doSomethingWithA() { /* etc. */ }
// A.hpp

struct B ;

struct A
{
   B * b ;
   void doSomethingWithB() ;
} ;
// B.hpp

struct A ;

struct B
{
   A * a ;
   void doSomethingWithA() ;
} ;
// A.cpp
#include "A.hpp"
#include "B.hpp"

void A::doSomethingWithB() { /* etc. */ }
// B.cpp
#include "B.hpp"
#include "A.hpp"

void B::doSomethingWithA() { /* etc. */ }
// foo.hpp
#ifndef __FOO_HPP__
#define __FOO_HPP__

struct foo
{
   int data ;
} ;

#endif // __FOO_HPP__
// bar.hpp
#ifndef __BAR_HPP__
#define __BAR_HPP__

#include "foo.hpp"

struct bar
{
   foo f ;
   void doSomethingWithFoo() ;
} ;
#endif // __BAR_HPP__
// bar.cpp
#include "bar.hpp"

void bar::doSomethingWithFoo()
{
  // Initialize f
  f.data = 0;
  // etc.
}