2017-02-02 3 views
1

私は簡単なテストエンティティコンポーネントシステムを作成しています。私は基本的にいくつかの派生クラスを持つComponentクラスを持っています。私はこれらのコンポーネントにいくつかのロジックを適用するいくつかのシステムを持っています。基本クラスから派生クラスポインタへのstatic_castが無効です

// Component.h 
// ------------ 
class Component 
{ 
public: 
    Component(); 
    ~Component(); 
} 


// ControlComponent.h 
// ------------------- 
#include <string> 
#include "Component.h" 

class ControlComponent : public Component 
{ 
public: 
    std::string input = ""; // store simple input instruction 
    ControlComponent(); 
    ~ControlComponent(); 
}; 


// ControlSystem.cpp 
void ControlSystem::update(Entity* entity) 
{ 
    vector<Component*>* components = entity->getComponents(); 

    for (Component* component : *components) 
    { 
     PositionComponent* pc = static_cast<PositionComponent*>(component); 
     ControlComponent* cc = static_cast<ControlComponent*>(component); 

     if (pc != nullptr && cc != nullptr) 
     { 
      std::cout << "Which direction would you like to go?" << std::endl; 
      std::string input; 
      std::cin >> input; 
      cc->input = input; // application breaks here 

      // Apply some logic... 
     } 
    } 
} 

ときベースComponent*から由来成分(PositionComponent*またはControlComponent*)とのいずれかにI static_cast両方の結果がでないときnullptr、私はcc->inputができないように、無効な値を取得する(つまり、キャストは成功しました)文字列から文字などに

を読んで、私はこのように、私のエンティティの工場に部品を配線:

void EntityFactory::wireUpPlayer(Entity* player) 
{ 
    player->addComponent(new HealthComponent()); 
    player->addComponent(new ControlComponent()); 
    player->addComponent(new PositionComponent()); 
} 

とT

void Entity::addComponent(Component* component) 
{ 
    m_components.push_back(component); 
} 

これらのコンポーネントは、有効なメモリ・アドレスを有することが示されているので、私は問題がどこから来ているか分からない:次のようにaddComponentのための彼の実装です。

+3

あなたは 'dynamic_cast'の機能を' static_cast'に帰属させています。これはうまく終了できません。 – IInspectable

答えて

5

static_castは、実行時に妥当性をチェックしません。キャストがコンパイルされると、実行時に変換が正常であるとみなされます。 nullポインタをキャストしていない場合は、static_castの結果はNULLポインタになりません。チェックされたキャストを取得するには、dynamic_castが必要であり、ポインタは多態型、つまり少なくとも1つの仮想関数を持つ型を指すように変換する必要があります。つまり、少なくとも1つの仮想機能を持つようにComponentを変更することを意味します。

+1

そして、 'Component'が派生しているので、仮想化はほぼ常に正しいことです。 – IInspectable

+0

@IInspectable - 多分、継承だけではあまり話せません。オブジェクトの存続期間がどのように管理されているかによって異なります。基本型のポインタを介して派生型のオブジェクトを削除するようにデザインで呼び出す場合、基本型のデストラクタは仮想でなければならないというルールがあります。 –

+0

真。しかし、コレクション内の基本クラスへのポインタを保持することによって、OPがやっているように見えます。 – IInspectable

3

ときベースComponent*から由来成分(PositionComponent*またはControlComponent*)とのいずれかにI static_cast両方の結果がでないときnullptr ...

からキャストする場合(つまり、キャストは成功しました)基本クラスを派生クラスに変換すると、 static_castはコンパイラに「私を信じて、私がやっていることを知っている」と伝えています。つまり、たとえ でも有効であれば、が合法であれば、それは「成功」し、非 nullptrを返します。実行時に合法でない場合、あるクラスのインスタンスを別のクラスのように使用しようとすると、未定義の動作が発生します。

代わりにdynamic_castを使用してください。

+0

これは未定義の動作なので、ヌルポインタなどが得られるかもしれません。 –

1

Pete BeckerとJosh Kelleyが言っているように、dynamic_castを使用し、少なくとも1つの機能をvirtualと設定する必要があるとも思います。そうしないと、コンパイラは継承を記録せず、dynamic_castはおそらくnullptrを返します。継承を行うときには、クラスのデストラクタを仮想にすることをお勧めします。これは、管理されていないリソースを派生クラスのデストラクタで処理する必要があり、基本クラスへのポインタしか持たない場合でも、デストラクタが仮想である限り、派生クラスのデストラクタは呼び出されます。 When to use virtual destructors?

関連する問題