前向声明的循环包含和继承导致 C2504 基数 class 未定义
Circular Inclusion and Inheritence with Forward Declarations Leads to C2504 base class undefined
我在 PlayerController.h 中收到 C2504 编译错误,说我的基础 class(可更新)未定义。我已经搜索了几个小时来寻找解决循环包含继承问题的方法,他们的解决方案是删除循环包含并且只使用前向声明。据我了解,如果没有调用前向声明的 class 中的任何方法,则此方法有效。但是,在我的程序中,我的 Updateables class 在其成员继承的 gameObject 对象上调用一个方法,而 GameObjects 也在其成员 Updateables 上调用方法。因此,Updateables 需要包含 GameObject.h,而 GameObjects 需要包含 Updateables.h。这导致 PlayerController.h 中的 C2504 表示找不到基础 class 可更新。
这是我的相关 classes:
Component.h
#pragma once
#include "Vector3.h"
class GameObject;
class Component {
public:
GameObject* gameObject = nullptr;
Component();
};
Component.cpp
#include "Component.h"
Component::Component() {}
Updateable.h
#pragma once
#include "Component.h"
#include "GameObject.h"
class GameObject;
class Updateable : public Component {
public:
~Updateable();
virtual void update() = 0;
};
Updateable.cpp
#include "Updateable.h"
Updateable::~Updateable() {
if (gameObject) {
gameObject->removeUpdateable(this);
}
}
GameObject.h
#pragma once
#include "Updateable.h"
#include "GameManager.h"
class Updateable;
class GameObject {
public:
GameObject();
~GameObject();
void runUpdateables();
void addUpdateable(Updateable* updateable);
void removeUpdateable(Updateable* updateable);
private:
vector<Updateable*> updateables;
};
GameObject.cpp
#include "GameObject.h"
GameObject::GameObject() {
updateables = vector<Updateable*>();
GameManager::addGameObject(this);
}
GameObject::~GameObject() {
GameManager::removeGameObject(this);
}
void GameObject::runUpdateables() {
for (unsigned int i = 0; i < updateables.size(); i++) {
updateables[i]->update();
}
}
void GameObject::addUpdateable(Updateable* updateable) {
updateables.push_back(updateable);
updateable->gameObject = this;
}
void GameObject::removeUpdateable(Updateable* updateable) {
auto it = find(updateables.begin(), updateables.end(), updateable);
if (it != updateables.end()) {
updateables.erase(it);
}
}
PlayerController.h
#pragma once
#include "Updateable.h"
//#include "GameObject.h"
#include "Input.h"
class Updateable;
class PlayerController : public Updateable {
public:
float speed = 5.0f;
void update();
};
PlayerController.cpp
#include "PlayerController.h"
void PlayerController::update() {
float x = 0;
if (Input::getKeyDown(GLFW_KEY_A)) {
x = -speed;
}
if (Input::getKeyDown(GLFW_KEY_D)) {
x = speed;
}
cout << x << endl;
gameObject->getRigidBody()->velocity.x = x;
//yes this is a method in GameObject that I removed from this post
//because it would take up more space, rigidbody.h does not create
//a circular dependency
}
GameManager.h
#pragma once
#include "GameObject.h"
#include "PlayerController.h"
class GameManager {
public:
static void init();
static void addGameObject(GameObject* go);
static void removeGameObject(GameObject* go);
static void onFrame();
private:
static vector<GameObject*> gameObjects;
static GameObject* box;
GameManager.cpp
#include "GameManager.h"
vector<GameObject*> GameManager::gameObjects;
GameObject* GameManager::box;
void GameManager::init() {
gameObjects = vector<GameObject*>();
box = new GameObject();
box->addUpdateable(new PlayerController());
}
void GameManager::addGameObject(GameObject* go) {
gameObjects.push_back(go);
}
void GameManager::removeGameObject(GameObject* go) {
auto it = find(gameObjects.begin(), gameObjects.end(), go);
if (it != gameObjects.end()) {
gameObjects.erase(it);
}
}
void GameManager::onFrame() {
for (unsigned int i = 0; i < gameObjects.size(); i++) {
gameObjects[i]->runUpdateables();
}
}
这是确切的错误消息:Error C2504 'Updateable': base class undefined Basic Platformer c:\users\default.sixcore-pc\documents\visual studio 2015\projects\basic platformer\basic platformer\playercontroller.h 9
后代 class 必须知道基数 class 的完整定义。前向声明是不够的和无用的。
你的很多文件都有 #include "Class.h"
和 class Class;
声明。你永远不需要两者;使用其中之一。
class X
的定义必须在以下情况下可见:
- 访问
X
的成员
- 正在创建类型为
X
的对象
- 定义从
X
派生的 class
- 使用
X
作为模板的模板参数,要求相应的模板参数是完整类型(例如标准库容器对其元素类型的要求)。请注意,这适用于使用 X
而不是 X*
.
在其他情况下(例如创建指向 X
的指针或声明接受返回 X
的函数),非定义声明 (class X;
) 就足够了。
使用这些规则(加上必要时将函数体从头文件移动到源文件),您可以解决任何循环依赖问题。
如要直接处理您的文件:
Updateable.h
不需要#include "GameObject.h"
。它甚至不需要 GameObject
. 的前向声明
GameObject.h
不需要其中的任何两个 #include
。
GameManager.h
不需要任何 #include
。不过它需要 class GameObject;
的声明。
我在 PlayerController.h 中收到 C2504 编译错误,说我的基础 class(可更新)未定义。我已经搜索了几个小时来寻找解决循环包含继承问题的方法,他们的解决方案是删除循环包含并且只使用前向声明。据我了解,如果没有调用前向声明的 class 中的任何方法,则此方法有效。但是,在我的程序中,我的 Updateables class 在其成员继承的 gameObject 对象上调用一个方法,而 GameObjects 也在其成员 Updateables 上调用方法。因此,Updateables 需要包含 GameObject.h,而 GameObjects 需要包含 Updateables.h。这导致 PlayerController.h 中的 C2504 表示找不到基础 class 可更新。
这是我的相关 classes:
Component.h
#pragma once
#include "Vector3.h"
class GameObject;
class Component {
public:
GameObject* gameObject = nullptr;
Component();
};
Component.cpp
#include "Component.h"
Component::Component() {}
Updateable.h
#pragma once
#include "Component.h"
#include "GameObject.h"
class GameObject;
class Updateable : public Component {
public:
~Updateable();
virtual void update() = 0;
};
Updateable.cpp
#include "Updateable.h"
Updateable::~Updateable() {
if (gameObject) {
gameObject->removeUpdateable(this);
}
}
GameObject.h
#pragma once
#include "Updateable.h"
#include "GameManager.h"
class Updateable;
class GameObject {
public:
GameObject();
~GameObject();
void runUpdateables();
void addUpdateable(Updateable* updateable);
void removeUpdateable(Updateable* updateable);
private:
vector<Updateable*> updateables;
};
GameObject.cpp
#include "GameObject.h"
GameObject::GameObject() {
updateables = vector<Updateable*>();
GameManager::addGameObject(this);
}
GameObject::~GameObject() {
GameManager::removeGameObject(this);
}
void GameObject::runUpdateables() {
for (unsigned int i = 0; i < updateables.size(); i++) {
updateables[i]->update();
}
}
void GameObject::addUpdateable(Updateable* updateable) {
updateables.push_back(updateable);
updateable->gameObject = this;
}
void GameObject::removeUpdateable(Updateable* updateable) {
auto it = find(updateables.begin(), updateables.end(), updateable);
if (it != updateables.end()) {
updateables.erase(it);
}
}
PlayerController.h
#pragma once
#include "Updateable.h"
//#include "GameObject.h"
#include "Input.h"
class Updateable;
class PlayerController : public Updateable {
public:
float speed = 5.0f;
void update();
};
PlayerController.cpp
#include "PlayerController.h"
void PlayerController::update() {
float x = 0;
if (Input::getKeyDown(GLFW_KEY_A)) {
x = -speed;
}
if (Input::getKeyDown(GLFW_KEY_D)) {
x = speed;
}
cout << x << endl;
gameObject->getRigidBody()->velocity.x = x;
//yes this is a method in GameObject that I removed from this post
//because it would take up more space, rigidbody.h does not create
//a circular dependency
}
GameManager.h
#pragma once
#include "GameObject.h"
#include "PlayerController.h"
class GameManager {
public:
static void init();
static void addGameObject(GameObject* go);
static void removeGameObject(GameObject* go);
static void onFrame();
private:
static vector<GameObject*> gameObjects;
static GameObject* box;
GameManager.cpp
#include "GameManager.h"
vector<GameObject*> GameManager::gameObjects;
GameObject* GameManager::box;
void GameManager::init() {
gameObjects = vector<GameObject*>();
box = new GameObject();
box->addUpdateable(new PlayerController());
}
void GameManager::addGameObject(GameObject* go) {
gameObjects.push_back(go);
}
void GameManager::removeGameObject(GameObject* go) {
auto it = find(gameObjects.begin(), gameObjects.end(), go);
if (it != gameObjects.end()) {
gameObjects.erase(it);
}
}
void GameManager::onFrame() {
for (unsigned int i = 0; i < gameObjects.size(); i++) {
gameObjects[i]->runUpdateables();
}
}
这是确切的错误消息:Error C2504 'Updateable': base class undefined Basic Platformer c:\users\default.sixcore-pc\documents\visual studio 2015\projects\basic platformer\basic platformer\playercontroller.h 9
后代 class 必须知道基数 class 的完整定义。前向声明是不够的和无用的。
你的很多文件都有 #include "Class.h"
和 class Class;
声明。你永远不需要两者;使用其中之一。
class X
的定义必须在以下情况下可见:
- 访问
X
的成员
- 正在创建类型为
X
的对象
- 定义从
X
派生的 class
- 使用
X
作为模板的模板参数,要求相应的模板参数是完整类型(例如标准库容器对其元素类型的要求)。请注意,这适用于使用X
而不是X*
.
在其他情况下(例如创建指向 X
的指针或声明接受返回 X
的函数),非定义声明 (class X;
) 就足够了。
使用这些规则(加上必要时将函数体从头文件移动到源文件),您可以解决任何循环依赖问题。
如要直接处理您的文件:
Updateable.h
不需要#include "GameObject.h"
。它甚至不需要GameObject
. 的前向声明
GameObject.h
不需要其中的任何两个#include
。GameManager.h
不需要任何#include
。不过它需要class GameObject;
的声明。