c++标题保持理智
在使用 C++ 编码时,我似乎遇到的最大问题是,您必须先声明一个类,然后才能引用它。假设我有两个像这样的头文件...
Header1.h
#include "Header2.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage;
class Hello
{
public:
string Message;
HelloPackage * Package;
Hello():Message("")
{
}
Hello(string message, HelloPackage * pack)
{
Message = message;
Package = pack;
}
void Execute()
{
cout << Message << endl;
//HelloPackage->NothingReally doesn't exist.
//this is the issue essentially
Package->NothingReally(8);
}
};
Header2.h
#include "Header1.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage
{
public:
deque<Hello> Hellos;
HelloPackage()
{
Hellos = deque<Hello>();
}
int AddHello(string Message)
{
Hellos.push_back(Hello(Message,this));
}
void ExecuteAll()
{
for each(Hello h in Hellos)
h.Execute();
}
int NothingReally(int y)
{
int a = 0;
a += 1;
return a + y;
}
}
我想知道的是,是否有任何优雅的解决方案来处理这些问题?在 C# 和 Java 中,您不受这种“线性”编译的限制。
The biggest problem I seem to run into when coding in c++ is the fact that you must declare a class before you can reference it. Say I have two header file like this...
Header1.h
#include "Header2.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage;
class Hello
{
public:
string Message;
HelloPackage * Package;
Hello():Message("")
{
}
Hello(string message, HelloPackage * pack)
{
Message = message;
Package = pack;
}
void Execute()
{
cout << Message << endl;
//HelloPackage->NothingReally doesn't exist.
//this is the issue essentially
Package->NothingReally(8);
}
};
Header2.h
#include "Header1.h"
#include <deque>
#include <string>
#include <iostream>
using namespace std;
class HelloPackage
{
public:
deque<Hello> Hellos;
HelloPackage()
{
Hellos = deque<Hello>();
}
int AddHello(string Message)
{
Hellos.push_back(Hello(Message,this));
}
void ExecuteAll()
{
for each(Hello h in Hellos)
h.Execute();
}
int NothingReally(int y)
{
int a = 0;
a += 1;
return a + y;
}
}
What I'm wondering is, is there any elegant solution for dealing with these issues? In say c#, and java, you're not restricted by this "linear" compiling.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这对您有用的原因是,如果您愿意,您可以使用要引用的类的前向声明,而不包含该文件。
The reason this will work for you is because you can then use forward declarations of the class you want to reference without including the file if you so wish.
除了代码中的这些问题之外,回答您的问题:正常方法是转发声明类 - 不要在标头中包含标头(除非必须这样做)。
Besides these problems with your code, to answer your question : normal way is to forward declare classes - not to include headers in headers (unless you have to).
如果你遵循一些基本规则,那就一点也不尴尬了。但与 Java 或 C# 相比,您必须自己遵循这些规则,编译器和/或语言规范不会强制执行。
其他答案已经指出了这一点,但我将在这里回顾一下,以便您将其放在一个地方:
使用 包括守卫。它们确保您的标头(以及您的类定义)仅包含一次。
通常,您需要将方法的声明和实现分开。这使得头文件更具可重用性,并且会减少编译时间,因为头文件通常需要比 CPP(即实现)文件更少的 #include。
在标头中,使用前向声明而不是包含。仅当您仅使用相应类型的名称,但不需要知道任何“内部结构”时,这才有可能。原因是前向声明只是告诉编译器某个名称存在,而不是它包含的内容。
这是 Bar 类的前向声明:
在这里,编译器会知道某个地方有一个 Bar,但它不知道它有哪些成员。
仅在 CPP 文件中使用“using namespace xyz”,而不是在标头中。
好吧,这是您的示例代码,经过修改以满足这些规则。我只显示Hello类,HelloPackage将相应地分为头文件和CPP文件。
Hello.h (在您的示例中是 Header1.h)
Hello.cpp
可能出现的一个问题是为什么需要包含字符串。你不能也直接声明字符串类吗?
不同之处在于您使用字符串作为嵌入成员,而不使用指向字符串的指针。这没问题,但它强制您使用 #include,因为编译器必须知道 Hello 类中的字符串实例需要多少空间。
If you follow a few basic rules, it is not awkward at all. But in comparison to e.g. Java or C#, you have to follow these rules by yourself, the compiler and/or language spec does not enforce it.
Other answers already noted that, but I will recap here so you have it in one place:
Use include guards. They make sure that your header (and thus your class definition) is only included once.
Normally, you will want to separate the declaration and implementation of your methods. This makes the header files more reusable and will reduce compilation time, because the header requires normally fewer #includes than the CPP (i.e. implementation) file.
In the header, use forward declarations instead of includes. This is possible only if you just use the name of the respective type, but don't need to know any "internals". The reason for this is that the forward declaration just tells the compiler that a certain name exists, but not what it contains.
This is a forward declaration of class Bar:
Here, the compiler will know that there is a Bar somewhere, but it does not know what members it has.
Use "using namespace xyz" only in CPP files, not in headers.
Allright, here comes your example code, modified to meet these rules. I only show the Hello class, the HelloPackage is to be separated into header and CPP file accordingly.
Hello.h (was Header1.h in your example)
Hello.cpp
One question that may arise is why is the include for string is needed. Couldn't you just forward declare the string class, too?
The difference is that you use the string as embedded member, you don't use a pointer to string. This is ok, but it forces you to use #include, because the compiler must know how much space a string instance needs inside your Hello class.