C ++类继承混淆

时间:2012-03-08 22:03:17

标签: c++ inheritance

当包含所有相关标题时,为什么会出现“错误C2504:'CEntity':基类未定义”错误?

我有一个CMap可以完成大部分繁重的工作:

// CMap.h
#ifndef _CMAP_H_
#define _CMAP_H_
#include "CEntity.h"
class CMap {
    public:
        CMap(void);
        void OnLoad();
        void OnRender();
        std::vector<CTile*> TileList;
};
#endif

CMap中的一件事是Tiles列表:

// CTile.h
#ifndef _CTILE_H_
#define _CTILE_H_
class CEntity; // forward declaration

class CTile {
    public:
        CTile(void);
        std::vector<CEntity*> EntityList;
        char Label[0];
};
#endif

每个Tile包含一个实体列表:

// CEntity.h
#ifndef _CENTITY_H_
#define _CENTITY_H_
class CEntity {
    public:
        CEntity(void);
        char Label[0];
};
#endif

还有各种CEntity的孩子:

// CEntity_Buggy.h
#ifndef _CENTITY_BUGGY_H_
#define _CENTITY_BUGGY_H_
#include "CEntity.h"
class CEntity_Buggy : public CEntity {
    public:
        CEntity_Buggy(void);    
};
#endif

现在,我的主要地图加载例程工作正常,渲染路由也是如此,这需要查看Tiles以获取一些信息:

// CMap.cpp
#include "CMap.h"

void CMap::OnLoad() {
    ...
}

void CMap::OnRender() {
    /* here would be some rendering code ... */

    std::vector<CTile*>::iterator i;
    for (i=this->TileList.begin(); i!=this->TileList.end(); ++i) {
        CTile* tile = *i;

        for(unsigned int i = 0; i < tile->EntityList.size(); i++) {
            label[0] = tile->EntityList[i]->Label[0];
        }
    }
}

工作正常,到目前为止,在完整的应用程序中,它绘制单元格,并添加来自“常驻”实体的标签。 当我想将一些特定的实体子类放入系统时,问题出现了:

// CMap.h
#include "CEntity_Buggy.h" // add this to the header

// CMap.cpp
#include "CMap.h"

void CMap::OnLoad() {
    CEntity_Buggy buggy;
    buggy.OnLoad();
}

现在我收到很多\centity_buggy.h(18): error C2504: 'CEntity' : base class undefined错误,但我不确定原因。我的CEntity_Buggy.h包含CEntity.h。

完整的当前(这是第一个C ++项目,所以它有很大的缺陷)是available on GitHub,如果这有帮助的话。

2 个答案:

答案 0 :(得分:3)

我怀疑这里的具体原因包括:

  • CEntity.h包括CCamera.h
  • CCamera.h包括CMap.h
  • CMap.h包括CEntity_Buggy.h

因此CEntity.h导致在定义CEntity之前包含CEntity_Buggy.h。在这种情况下,它看起来不像CMap.h真的需要CEntity_Buggy.h - 你可能只是把它包含在cpp中。

一般情况下,避免在人类可能的地方包含.h文件。前瞻声明是你的朋友:)

答案 1 :(得分:2)

取出非标准的#pragma一次并进行完全重建。

您是否在Visual Studio中打开了预编译的标头?这是一个构建时间的bugtrap。

仅包含一次的便携式方法

#ifndef IDENTIFIER
#define IDENTIFIER

// header contents

#endif

IDENTIFIER是根据标题名称选择的,如果你很聪明,还有一些额外的字符可以减少它与任何东西发生冲突的可能性。例如。 CENTITY_H_4D59_3FC4(随机选择的十六进制数字)。

一个不错的编译器(例如gcc)会识别这个“ifdef ritual”并且实际上不会读取标题,因此它与#pragma once一样有效。

我写这篇文章是因为显然centity.h标题定义了CEntity类,它被包含在派生类CEntityBuggy的定义之上。那为什么不定义这个类呢?也许#pragma once是错误的并且已经吃掉了标头,或者编译器正在从预编译的标头缓存中反复出现一些过时的标头材料。

像这样的构建时间会让你对正确的代码感到头疼。