2017-07-11 20 views
0

PlayerController.hにC2504コンパイルエラーが発生しました。私の基底クラス(Updateable)は未定義です。私は、継承問題を持つ循環的な包含への解決のために数時間を探し、その解決策は円形の包含物を除去することであり、前方宣言を使用することです。私が理解する限り、前方宣言されたクラスからのメソッドが呼び出されない場合、これは機能します。しかし、私のプログラムでは、私のUpdateablesクラスは、メンバーのgameObjectオブジェクトを継承したメソッドを呼び出し、GameObjectsはメンバーのUpdateableのメソッドも呼び出します。このため、UpdateablesにはGameObject.hを含める必要があり、GameObjectsにはUpdateables.hを含める必要があります。これによりPlayerController.hのC2504に、基本クラスUpdateableが見つかりませんというメッセージが表示されます。 Component.hForward宣言による循環包含と継承C2504基底クラスへのリードが定義されていません

#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(); 
    } 
} 

ここでは、正確なエラーメッセージです:エラーC2504 '更新可能':ベースクラス未定義の基本的なプラットのC:\ユーザー\ default.sixcore -pc \ documents \ visual studio 2015 \ projects \ basic platformer \ basic platformer \ playercontroller.h 9

+0

なぜ、 'PlayerController'を' Updateable'で宣言していますか? –

+0

あなたは 'Component'を使っています。あなたは' Updatable'でそれを使用していますので、そのコンストラクタを定義する必要があります。 – Galik

+0

オブジェクトが使用される*ソース*ファイルに必要なヘッダーファイルを含める必要があります。適切な前方宣言を含むヘッダーファイルには、ヘッダーファイルをまったく含める必要はありません。 –

答えて

2

多くのファイルには、#include "Class.h"class Class;の両方の宣言があります。あなたは両方を必要としません。どちらか一方を使用してください。

  • Xなどを使用してX
  • から派生したクラスを定義するタイプX
  • のオブジェクトを作成X
  • のメンバーにアクセスする:とき

    クラスXの定義が表示されなければなりません対応するテンプレートパラメータを完全な型にする必要があるテンプレートへのテンプレート引数(標準ライブラリコンテナが必要とするものその要素タイプの)。これは、Xを使用する場合に適用され、ではなく、適用されます。

  • (例えば Xへのポインタを作成または Xを返す関数の撮影を宣言するような)他の場合において

、非定義宣言(class X;)が十分です。

これらのルール(必要に応じてヘッダからソースファイルに関数本体を移動する)を使用すると、循環依存関係の問題を解決できます。


は直接提示されたファイルに対処するには、次の

  • Updateable.h

    #include "GameObject.h"する必要はありません。それはGameObjectの前方宣言も必要ない。
  • GameObject.hは、2つのうちのいずれも必要ありません。
  • GameManager.hは、#includeを必要としません。しかし、それはclass GameObject;の宣言が必要です。
0

下位クラスは、基本クラスの完全な定義を知っていなければなりません。フォワード宣言は十分ではなく、役に立たない。

+0

を追加しました。完全な定義は、クラスが*インスタンス化されたとき、またはメンバーにアクセスするときにのみ必要です。継承のために必要なのは宣言されたシンボルだけです。 –

+0

@Someprogrammerdude私はそれが本当ではないのだろうかと思います。派生クラスを定義するには、すべての基本クラスの定義が必要です。それ以外の場合はレイアウトとサイズを把握できませんでした。 – Angew

+0

@Angewクラスがインスタンス化されたときに完全な定義が利用可能な場合(例えば、必要なすべてのヘッダファイルを含めるなど)、ヘッダファイルで 'class A; class B:public A {...}; 'クラス' A 'のヘッダファイルを明示的にインクルードする必要はありません。 –

関連する問題