而不是做
#include "MyClass.cpp"
我想做
#include "MyClass.h"
我在网上看到不这样做被认为是不好的做法。
答案 0 :(得分:13)
首先,我们来看一些简单的例子:
struct ClassDeclaration; // 'class' / 'struct' mean almost the same thing here
struct ClassDefinition {}; // the only difference is default accessibility
// of bases and members
void function_declaration();
void function_definition() {}
extern int global_object_declaration;
int global_object_definition;
template<class T> // cannot replace this 'class' with 'struct'
struct ClassTemplateDeclaration;
template<class T>
struct ClassTemplateDefinition {};
template<class T>
void function_template_declaration();
template<class T>
void function_template_definition() {}
翻译单元(TU)是单个源文件(应该是** .cpp *文件)及其包含的所有文件,包括等等。换句话说:预处理单个文件的结果。
包含防护是一种破解工作,缺乏真正的模块系统,使标头成为一种有限的模块;为此,不止一次包括相同的标题不得产生不利影响。
通过制作后续#includes no-ops来包含警卫工作,其中包含第一个包含的定义。由于它们的性质有限,控制标题选项的宏在整个项目中应该是一致的(奇怪的标题,如&lt; assert.h&gt;导致问题),所有#includes的公共标题应该在任何名称空间,类等之外,通常在任何文件的顶部。
查看我的包含警示naming advice,包括generate include guards的简短程序。
类,函数,对象和模板几乎可以在任何地方声明,可以声明任意数字时间,必须在以任何方式引用它们之前声明。在一些奇怪的情况下,您可以在使用它们时声明类;这里不会涉及。
类;当您为特定类包含标头时,通常会发生这种情况。 函数和对象必须在一个TU中定义一次;当您在** .cpp *文件中实现它们时,通常会发生这种情况。但是,内联函数,包括类定义中的隐式内联函数,可以在多个TU中定义,但定义必须相同。
出于实际目的 [2] , templates (类模板和函数模板)仅在头文件中定义,如果要使用单独的文件,则使用另一个标题 [3] 。
[1] 由于最多一次的限制,标题使用包含防护来防止多次包含,从而防止多个定义错误。
[2] 我不会在这里讨论其他可能性
[3] 将其命名为 blahblah_detail.hpp , blahblah_private.hpp ,或类似名称,如果您想记录它是非公开的。
所以,虽然我确定上面的所有内容到目前为止都是一个很大的漏洞,但它不应该是一篇关于应该占用几章的页面,所以请将它作为一个简短的参考。但是,理解上述概念很重要。使用这些,这里是一个简短的指南列表(但不是绝对规则):
(这是回答你问题的一小部分,但你需要上面的大部分才能到达这里。)
构建时,构建系统将经历几个步骤,其中重要的步骤是:
我建议你学习制作的基本知识,因为它很受欢迎,很容易理解,而且很容易上手。但是,它是一个有几个问题的旧系统,你需要在某些时候切换到别的东西。
选择一个构建系统几乎是一种宗教体验,比如选择一个编辑器,除了你必须与更多的人合作(每个人都在同一个项目上工作),并且可能会受到先例和惯例的限制。你可以使用一个为你处理相同细节的IDE,但是使用全面的构建系统并没有真正的好处,你真的应该知道它在幕后做了什么。
#ifndef EXAMPLE_INCLUDE_GUARD_60497EBE580B4F5292059C8705848F75
#define EXAMPLE_INCLUDE_GUARD_60497EBE580B4F5292059C8705848F75
// all project-specific macros for this project are prefixed "EXAMPLE_"
#include <ostream> // required headers/"modules"/libraries from the
#include <string> // stdlib, this project, and elsewhere
#include <vector>
namespace example { // main namespace for this project
template<class T>
struct TemplateExample { // for practical purposes, just put entire
void f() {} // definition of class and all methods in header
T data;
};
struct FooBar {
FooBar(); // declared
int size() const { return v.size(); } // defined (& implicitly inline)
private:
std::vector<TemplateExample<int> > v;
};
int main(std::vector<std::string> args); // declared
} // example::
#endif
#include "example.hpp" // include the headers "specific to" this implementation
// file first, helps make sure the header includes anything it needs (is
// independent)
#include <algorithm> // anything additional not included by the header
#include <iostream>
namespace example {
FooBar::FooBar() : v(42) {} // define ctor
int main(std::vector<std::string> args) { // define function
using namespace std; // use inside function scope, if desired, is always okay
// but using outside function scope can be problematic
cout << "doing real work now...\n"; // no std:: needed here
return 42;
}
} // example::
#include <iostream>
#include "example.hpp"
int main(int argc, char const** argv) try {
// do any global initialization before real main
return example::main(std::vector<std::string>(argv, argv + argc));
}
catch (std::exception& e) {
std::cerr << "[uncaught exception: " << e.what() << "]\n";
return 1; // or EXIT_FAILURE, etc.
}
catch (...) {
std::cerr << "[unknown uncaught exception]\n";
return 1; // or EXIT_FAILURE, etc.
}
答案 1 :(得分:3)
这称为separate compilation model。您将类声明包含在需要它们的每个模块中,但定义它们only once。
答案 2 :(得分:2)
除了隐藏cpp文件中的实现细节(查看其他回复)之外,您还可以通过类前向声明来隐藏结构细节。
class FooPrivate;
class Foo
{
public:
// public stuff goes here
private:
FooPrivate *foo_private;
};
表达式class FooPrivate
表示FooPrivate
完全定义在其他位置(最好在Foo
实现所在的同一文件中,Foo
之前的内容。这样就可以确保Foo(Private)的实现细节不会通过头文件公开。
答案 3 :(得分:2)
您不需要包含.c或.cpp文件 - 编译器将编译它们,无论它们是否包含在其他文件中。但是,如果其他文件不知道类/ methods / functions / global vars /包含在其中的任何内容,则.c / .cpp文件中的代码是无用的。这就是标题发挥作用的地方。在标题中,您只放置声明,例如:
//myfile.hpp
class MyClass {
public:
MyClass (void);
void myMethod (void);
static int myStaticVar;
private:
int myPrivateVar;
};
现在,所有#include“myfile.hpp”的.c / .cpp文件都能够创建MyClass的实例,在myStaticVar上运行并调用MyClass :: myMethod(),即使这里没有实际的实现!见
实现(实际代码)进入myfile.cpp,在那里你告诉编译器你的所有东西:
//myfile.cpp
int MyClass::myStaticVar = 0;
MyClass::MyClass (void) {
myPrivateVar = 0;
}
void MyClass::myMethod (void) {
myPrivateVar++;
}
你永远不会在任何地方包含这个文件,这绝对没有必要。
提示:创建一个main.hpp(或main.h,如果您愿意 - 没有区别)文件并将所有#include放在那里。然后每个.c / .cpp文件只需要有这一行:#include“main.hpp”。这足以访问您在整个项目中声明的所有类,方法等。)。
答案 4 :(得分:1)
您不应包含源文件(.c或.cpp)。相反,您应该包含包含声明的相应头文件(.h)。源文件需要单独编译并链接在一起以获得最终的可执行文件。
答案 5 :(得分:1)
应在编译器脚本中定义Cpp文件,以便将其编译为目标文件。
你使用什么ide? 我假设您正在使用gcc编译,所以这里是将两个.cpp文件编译成一个可执行文件的命令
gcc -o myclasses.out myclass.cpp myotherclass.cpp
您应该只使用#include来包含类定义,而不是实现
答案 6 :(得分:1)
当您从.h / .hpp中包含类声明时,您需要注意的一件事是确保它只被包含一次。如果你不这样做,你会得到一些可能是神秘的编译器错误,这些错误会让你陷入困境。
要执行此操作,您需要使用#define告诉编译器仅在#define不存在时才包含该文件。
例如(MyClass.h):
#ifndef MYCLASS_H
#define MYCLASS_H
class MyClass
{
// Memebers and methods
}
#endif
// End of file
即使您将类声明包含在许多不同的.cpp文件中,也可以保证您的类声明只被包含一次。