C++ の動的キャストに関するいくつかのスレッドを読みましたが、すべてが悪い設計を示していると主張する人でいっぱいです。他の言語では、オブジェクトの型をチェックするときにあまり考えたことはありませんでした。ポリモーフィズムの代わりとして使用することはなく、強い結合が完全に受け入れられると思われる場合にのみ使用します。私が頻繁に遭遇するこれらの状況の 1 つは、すべて共通の基本クラスから派生したオブジェクトのリスト (私は C++ で std::vector を使用します) を持っていることです。リストは、さまざまなサブクラスを認識できるオブジェクトによって管理されます (多くの場合、管理オブジェクト クラス内のプライベート クラスの小さな階層です)。それらを 1 つのリスト (配列、ベクターなど) に保持することで、ポリモーフィズムの恩恵を受けることができますが、操作が特定のサブクラスのオブジェクトに対して作用することを意図している場合は、動的キャストなどを使用します。
私が見逃している動的キャストや型チェックなしで、この種の問題に対する別のアプローチはありますか? これらを何としても回避するプログラマーが、それらをどのように処理するのか、私は本当に興味があります。
私の説明が抽象的すぎる場合は、C++ で簡単な例を書くことができます (編集: 以下を参照)。
class EntityContacts {
private:
class EntityContact {
private:
virtual void someVirtualFunction() { }; // Only there to make dynamic_cast work
public:
b2Contact* m_contactData;
};
class InternalEntityContact : public EntityContact {
public:
InternalEntityContact(b2Fixture* fixture1, b2Fixture* fixture2){
m_internalFixture1 = fixture1;
m_internalFixture2 = fixture2;
};
b2Fixture* m_internalFixture1;
b2Fixture* m_internalFixture2;
};
class ExternalEntityContact : public EntityContact {
public:
ExternalEntityContact(b2Fixture* internalFixture, b2Fixture* externalFixture){
m_internalFixture = internalFixture;
m_externalFixture = externalFixture;
};
b2Fixture* m_internalFixture;
b2Fixture* m_externalFixture;
};
PhysicsEntity* m_entity;
std::vector<EntityContact*> m_contacts;
public:
EntityContacts(PhysicsEntity* entity)
{
m_entity = entity;
}
void addContact(b2Contact* contactData)
{
// Create object for internal or external contact
EntityContact* newContact;
if (m_entity->isExternalContact(contactData)) {
b2Fixture* iFixture;
b2Fixture* eFixture;
m_entity->getContactInExFixtures(contactData, iFixture, eFixture);
newContact = new ExternalEntityContact(iFixture, eFixture);
}
else
newContact = new InternalEntityContact(contactData->GetFixtureA(), contactData->GetFixtureB());
// Add object to vector
m_contacts.push_back(newContact);
};
int getExternalEntityContactCount(PhysicsEntity* entity)
{
// Return number of external contacts with the entity
int result = 0;
for (int i = 0; i < m_contacts.size(); ++i) {
ExternalEntityContact* externalContact = dynamic_cast<ExternalEntityContact*>(m_contacts[i]);
if (externalContact != NULL && getFixtureEntity(externalContact->m_externalFixture) == entity)
result++;
}
return result;
}
};
これは、box2d 物理を使用するゲームで衝突検出に使用するクラスの簡易バージョンです。box2d の詳細が、私が表示しようとしているものからあまり気を散らさないことを願っています。同じ方法で構造化されたさまざまなタイプのイベントハンドラーを作成する非常によく似たクラス「Event」があります(EntityContactの代わりに基本クラスEventHandlerのサブクラスを使用)。