私はかつて航空機のシミュレーションに取り組んだことがありますが、それは彼らが (やや紛らわしい) 「シミュレーション データベース」と呼んだものを持っていました。float や int や string などの変数を登録すると、人々はそれらを名前で検索し、それらへの参照を引き出すことができます。モデル (「SimModel」から派生したクラスのオブジェクト) を登録することもできます。私が RTTI を使用した方法は、特定のインターフェースを実装するモデルを検索できるようにすることでした。
SimModel* SimDatabase::FindModel<type*>(char* name="")
{
foreach(SimModel* mo in ModelList)
if(name == "" || mo->name eq name)
{
if(dynamic_cast<type*>mo != NULL)
{
return dynamic_cast<type*>mo;
}
}
return NULL;
}
SimModel 基本クラス:
class public SimModel
{
public:
void RunModel()=0;
};
インターフェースの例は「EngineModel」です。
class EngineModelInterface : public SimModel
{
public:
float RPM()=0;
float FuelFlow()=0;
void SetThrottle(float setting)=0;
};
次に、Lycoming および Continental エンジンを作成します。
class LycomingIO540 : public EngineModelInterface
{
public:
float RPM()
{
return rpm;
}
float FuelFlow()
{
return throttleSetting * 10.0;
}
void SetThrottle(float setting)
{
throttleSetting = setting
}
void RunModel() // from SimModel base class
{
if(throttleSetting > 0.5)
rpm += 1;
else
rpm -= 1;
}
private:
float rpm, throttleSetting;
};
class Continental350: public EngineModelInterface
{
public:
float RPM()
{
return rand();
}
float FuelFlow()
{
return rand;
}
void SetThrottle(float setting)
{
}
void RunModel() // from SimModel base class
{
}
};
さて、ここに誰かがエンジンを必要とするコードがあります:
.
.
EngineModelInterface * eng = simDB.FindModel<EngineModelInterface *>();
.
.
fuel = fuel - deltaTime * eng->FuelFlow();
.
.
.
コードはかなり疑似的ですが、アイデアが伝わることを願っています。1 人の開発者がエンジンに依存するコードを作成できますが、エンジン インターフェイスを実装するものがある限り、それが何であるかは気にしません。そのため、タンク内の燃料の量を更新するコードは、FindModel<>() 関数と、彼が使用したいと考えている純粋な仮想 EngineModel インターフェイスを除くすべてから完全に切り離されています。1 年後に誰かが新しいエンジン モデルを作成し、それを SimulationDatabase に登録すると、燃料を更新した上記の担当者が自動的に使用を開始します。実際には、実行時に新しいモデルをプラグイン (DLL) としてロードできるように作成し、SimulationDatabase に登録すると、FindModel<>() で見つけることができます。それらを探していたコードは、新しい DLL が存在する数か月前にコンパイルされ、DLL に組み込まれていました。また、SimModel から派生した新しいインターフェイスを追加することもできます。それらを 1 つの DLL で実装するものと、別の DLL でそれらを検索するものを使用して、両方の DLL をロードすると、モデルを取得するために FindModel<>() を実行できます。もう一方。メインアプリが構築されたとき、インターフェイス自体は存在しませんでしたが。
括弧書きとして、RTTI は常に DLL の境界を越えて機能するとは限りません。とにかくQtを使っていたので、qobject_cast
代わりにdynamic_cast
. すべてのクラスは QObject から継承する (そして moc を取得する) 必要がありましたが、qobject メタデータは常に利用可能でした。DLL を気にしない場合、または RTTI が DLL の境界を越えて機能するツールチェーン(ハッシュなどではなく文字列比較に基づく型比較) を使用している場合は、上記のすべてがdynamic_cast
問題なく機能します。