前向声明?,包括警卫?,或其他什么
Forward Declaration?, Include guard?, or something else?
我有一个名为 Token 的父类
我有两个子类,ErrorToken和EndToken。 这些类中的每一个都需要能够创建另一个类的对象,并通过函数调用将其返回。 每个都有自己单独的标头类。
因此,ErrorToken 需要能够创建一个新的 EndToken 对象并返回它,而 EndToken 需要能够创建一个新的 ErrorToken 对象并返回它。
成功做到这一点的最佳方法是什么? 我希望它尽可能与交叉编译器兼容,所以我不想使用一次编译指示。 (但这本质上是我正在寻找的)。
理想情况下,我希望能够做这样的事情...
#ifndef ErrorToken
#include "ErrorToken.h"
#endif
但这似乎永远不会奏效(我的猜测是错误的? 有人可以帮助我理解为什么吗?
我对前向声明的理解是它仅适用于函数签名和指针(这是正确的吗?),所以我认为这不适用于我的情况,因为我需要它能够运行构造函数......还是编译器只需要知道构造函数在那一刻退出?
好吧,使用前向声明。正如你所说,那里有数百万种解释,现在有数百万零一种:
ErrorToken.h:
#ifndef H_ERROR_TOKEN
#define H_ERROR_TOKEN
#include "Token.h"
class EndToken;
class ErrorToken : public Token
{
public:
EndToken makeEndToken();
};
#endif
EndToken.h:
#ifndef H_END_TOKEN
#define H_END_TOKEN
#include "Token.h"
class ErrorToken;
class EndToken : public Token
{
public:
ErrorToken makeErrorToken();
};
#endif
在每个实现文件中,您现在可以愉快地包含两个标头:
#include "ErrorToken.h"
#include "EndToken.h"
ErrorToken EndToken::makeErrorToken()
{
return ErrorToken(); // example
}
EndToken ErrorToken::makeEndToken()
{
return EndToken();
}
正如@James Kanze指出的那样,您可能会对C++的工作方式感到困惑。以下代码可能更符合您期望从 Java 获得的行为类型,并且在多态设计方式中更有意义:
class Token { virtual ~Token() {} };
class ErrorToken : public Token
{
std::unique_ptr<Token> makeEndToken();
};
class EndToken : public Token
{
std::unique_ptr<Token> makeErrorToken();
};
std::unique_ptr<Token> EndToken::makeErrorToken()
{
return { new ErrorToken; }
}
std::unique_ptr<Token> ErrorToken::makeEndToken()
{
return { new EndToken; }
}
由于您仅通过基指针处理对象,因此标头不需要了解有关其他派生类的任何信息。(我让你们将代码细分为文件;每个块都进入一个单独的文件。
为什么你的
#ifndef ErrorToken
错?首先,将其放在头文件中,其次确保某些内容确实定义了ErrorToken
包括守卫和转发声明可能会让你摆脱这个洞:
//"ErrorToken.h"
#ifndef ERROR_TOKEN_INCLUDED
#define ERROR_TOKEN_INCLUDED
class EndToken;
class ErrorToken
{
public:
EndToken DoSomething();
};
#endif
//"EndToken.h"
#ifndef END_TOKEN_INCLUDED
#define END_TOKEN_INCLUDED
class ErrorToken;
class EndToken
{
public:
ErrorToken DoSomething();
};
#endif
之前已经有几次关于循环依赖关系的讨论:这里,这里和这里
然后,您可以在 cpp 文件中完成大部分工作,其中包含另一个标头,以便它知道完整的类定义,而不仅仅是前向声明,并且可以使用它。
不过,先退后一步,问道:"他们真的需要了解彼此吗?
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 这个失败的测试是将零添加到空指针未定义的行为、编译器错误还是其他什么?
- 当一行中只有一个"#"而没有其他内容时,C++预处理器会做什么?
- 计时器坏了或者其他什么的
- 编译以下重载<<需要什么enable_if或其他提示?
- 在这种情况下,我们可以使用静态而不是朋友吗,还有其他解决方案是什么
- 附加包含目录和其他 #using 目录有什么区别?
- 谷神星求解器:残差函子使用的可变对象是否良好实践?还有什么其他选择
- 相同的代码,不同的结果?从其他项目包含有什么问题?
- 创建实例化所有其他类和子系统的类的目的是什么
- 设计问题:枚举或函数或其他什么
- 对C++中的字节字段使用char*或void*或其他什么
- 我应该使用SIMD还是向量扩展或其他什么
- 前向声明?,包括警卫?,或其他什么
- 自定义顶点处理器不起作用 - 矩阵乘法错误或其他什么?
- 字符串向量、列表或其他什么?C++
- 扩展类以进行调试:公共API、隐藏实现或其他什么
- 切换或其他什么
- c++应用程序保存并应用首选项模式(可能是boost或其他什么)
- 这个宏语句是合法的C++还是其他什么?如果它是合法的,它是如何运作的