C++,当你创建多个类时,你是否应该将它们放在自己的 .cpp/.h 对中

In C++, when you make multiple classes, are you supposed to put them each in their own .cpp/.h pair?

本文关键字:自己的 cpp 对中 创建 当你 C++ 是否      更新时间:2023-10-16

假设我有一个程序,如下所示

#include <iostream>
#include <algorithm>
class HelloWorlder
{
public: 
  HelloWorld();
  ~HelloWorld();
  void print_content() {std::cout << "Hello, world!"};
};
class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}
};
int main()
{
    HelloWorlder HW;
    HW.print_content();
    StringReverser SR;
    SR.reverse_and_print("Jon Skeet");
    return 0;
}

那么我应该将它们划分为main.cppHelloWorlder.hHelloWorlder.cppStringReverser.hStringReverser.cpp的文件;还是只使用main.cpp、一个.h和一个.cpp?如果是前者,那么如果其中一个类使用另一个类,如何将文件链接在一起?例如,如果我将第二个类更改为

class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}
private:
  HelloWorlder h;
}

那么我必须做类似的事情吗

字符串反向器.cpp

#include "StringReverser.h"
#include "HelloWorlder.h"
class StringReverser
{
public:
  Reverser();
  ~Reverser();
  void reverse_and_print(std::string & s) {std::reverse(s.begin(), s.end()); std::cout << s;}
private:
  HelloWorlder h;
}

还是我还有其他事情要做?

它是约定俗成的;两种做法都使用:小C++文件,每个类一个文件,或大C++文件,有几个相关的类和函数。

我不建议将每个类放入C++单独的源文件和头文件中(这几乎是 Java 需要的,而不是 C++ 中的)。我相信一个类在概念上属于某个"模块"(通常一个"模块"包含几个相关的类和函数)。

所以我建议在同一头文件中声明同一"模块"的相关类(例如 foo.hh),并在相关(或相同)的代码文件中实现这些类(例如,一个foo.cc或多个foo-bar.cc&foo-clu.cc&foo-dee.cc),每个类#include foo.hh

您通常希望避免使用非常短的C++文件(以避免大量的构建时间)。所以我更喜欢几千行的代码文件和几百行的头文件。在小型应用程序中(例如少于 3 万行代码),我可能只有一个通用头文件。而一个"模块"(目前这只是一个设计,没有C++11功能明确支持模块)通常由几个相关的类和函数组成。因此,我发现实现具有多个类的"模块"的源文件比几个微小的源文件更具可读性和可维护性。

避免使用非常短的源代码文件(例如一百行代码)是有原因的。您的C++程序将使用标准C++模板容器,因此将直接或间接#include几个标准标头,如<string><vector><map><set>等。实际上,这些标头可能会带来数千行(编译器将解析这些行)。例如,包括<vector><map>在我的GCC 4.9上带来了41130行。因此,仅包含这两个标头的一百行源文件需要花费大量时间来编译(并且通常需要在头文件中包含标准容器)。因此,具有十个源文件(每个源文件几千行)的程序将比由数百个源文件(每个源文件几百行)组织的同一程序构建得更快。查看使用 g++ -Wall -C -E 获得的代码的预处理形式!

C++的未来版本可能有适当的模块(C++标准化委员会已经并将讨论这个问题,例如参见n4047)。今天C++11没有它们,所以我引用了"模块"。一些语言(Go,Rust,Ocaml,Ada等)已经有了适当的模块。而一个模块一般由几个相关的类、类型、函数、变量组成。

某些C++编译器能够预编译头文件。但这是特定于编译器的。使用 g++ 仅当您有一个公共头文件时,它才能正常工作。看到这个答案。

顺便说一句,你应该看看现有的自由软件C++代码。有些项目有很多小文件,有些项目有更少但更大的文件。两种方法都使用!

语言不需要将类放入单独的源文件和头文件中,但通常它会使范围更清晰和隔离

,在大多数情况下建议使用。

检查语言的作用域定义,特别是类作用域和文件(编译单元)作用域。

没有人强迫你这样做,但建议按照你说的去做:将这些类划分为它们自己的 .cpp/.h 文件(或者至少我会推荐它)。

这个问题在这里显示了如何将.cpp文件链接在一起。

您不需要将每个类放在其自己的文件中 C++.但是,如果您愿意,您可以这样做,通常建议这样做。

如何链接它们取决于您所在的平台?如果你在Windows中,并且你有Visual Studio,你只需要从调试菜单中选择"运行"或"调试"(这可能取决于你使用的版本,所以请检查你的特定版本)。如果你使用的是Linux,像这样的gcc简短教程会帮助你。

除了其他问题之外,分离也有一定的性能提升。 如果您有 5 个类,每个类都有自己的头文件,但 .cpp 文件仅使用其中两个类,则仅加载这两个标头是有意义的。 编译器必须处理更少的代码,而不是加载一个包含所有五个类定义的标头。 对于一个小项目来说,这没什么大不了的,但是当你开始向代码中添加数百个类时,有选择性可能会有它的性能优势。

这可以进一步扩展到使用函数和类原型而不是整个类文件,但为了您的问题,单独头文件中的类隔离是获得代码性能和组织的良好开端。

为了回答问题的另一部分,如果您的项目设置正确,编译器将自动编译其中引用的每个.cpp。 标题是另一回事。 只要您的.cpp文件仅引用它们所需的标头,您的代码就应该可以正常编译。 起初,这似乎有点难以管理,但经过一些练习后,您将擅长它,并发现您的代码层次结构易于导航和理解。