C++,当你创建多个类时,你是否应该将它们放在自己的 .cpp/.h 对中
In C++, when you make multiple classes, are you supposed to put them each in their own .cpp/.h pair?
假设我有一个程序,如下所示
#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.cpp
、HelloWorlder.h
、HelloWorlder.cpp
、StringReverser.h
和StringReverser.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文件仅引用它们所需的标头,您的代码就应该可以正常编译。 起初,这似乎有点难以管理,但经过一些练习后,您将擅长它,并发现您的代码层次结构易于导航和理解。
- Linux的Cpp上的计时器
- 没有为自己的结构调用列表推回方法
- 使用2个键的cpp-stl::优先级队列排序不正确
- 在他自己的方法中,有可能将一个对象取消引用到另一个对象吗
- 在c++中为我自己的基于指针的数组分配内存的正确方法
- 模板专业化可以进入我的.cpp吗?
- C++ 链接到单独的.cpp文件说"multiple definitions"
- 反向功能超出了我的 cpp 程序的范围
- C++从对象自己的类中删除对象
- 使用 std::optional,而不是自己的结构
- 子轴围绕父轴而不是他自己的轴旋转
- 如何使用connect将qml按钮与同一类的cpp函数连接起来
- 从不同的 cpp 调用回调函数会导致bad_function_call
- 这个C++编译器优化(在自身的实例上调用对象自己的构造函数)的名称是什么,它是如何工作的?
- 在 cpp 自己的版本中对字符串进行哈希处理
- cpp 对象方法是否有自己的堆栈帧
- C++,当你创建多个类时,你是否应该将它们放在自己的 .cpp/.h 对中
- 在自己的.cpp中定义一个结构,然后在main中使用它
- G++ makefile,多个 CPP 每个都有自己的 main()
- 是否有任何cpp函数或对象(不包括从c继承的)不是线程安全的,即使每个线程对自己的数据进行操作