c ++多态性:前向宣言?,包括警卫?或其他什么?

时间:2013-09-12 08:15:39

标签: c++ null polymorphism forward-declaration include-guards

我知道有一百万个主题在那里解释如何使用前瞻性声明并包括警卫。我来自java,我不必担心这些事情。这是我的第一个c ++程序,对我来说很简单(并给出建议)。

这是我的问题......

我有一个名为Token的父类

我有两个子类,ErrorToken和EndToken 这些类中的每一个都需要能够创建另一个的对象,并通过函数调用返回它。每个人都有自己独立的标题类。

因此,ErrorToken需要能够创建一个新的EndToken对象并将其返回,并且EndToken需要能够创建一个新的ErrorToken对象并将其返回。

成功实现这一目标的最佳途径是什么?我希望如果它尽可能兼容交叉编译器,那么<​​strong>我不想一次使用pragma。(但这基本上就是我正在寻找的东西)。

理想情况下,我希望能够做到这样的事情......

#ifndef ErrorToken
#include "ErrorToken.h"
#endif

但这似乎永远不会奏效(我的猜测是错的?有人可以帮我理解原因吗?)。

我对前向声明的理解是它只适用于函数签名和指针(这是正确的吗?),所以我认为这不适用于我的情况,因为我需要它才能运行构造函数。 .or编译器是否需要知道构造函数在那一刻退出了?

2 个答案:

答案 0 :(得分:2)

好吧,使用前向声明。正如你所说,那里有数以百万计的解释,现在有数百万和一个:

<强> 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; }
}

由于您只是通过基本指针处理对象,因此标题不需要知道关于其他派生类的任何。 (我留给你把代码细分为文件;每个块进入一个单独的文件。)

答案 1 :(得分:1)

为什么是你的

#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

先前有几个关于循环依赖的讨论:hereherehere
然后,您可以在cpp文件中执行大量工作,其中包含其他标头,因此它知道完整的类定义,而不仅仅是前向声明,并且可以使用它。
先退一步然后问:“他们真的需要了解彼此吗?”