我曾经做过一次飞机模拟,他们(有点令人困惑)称之为“模拟数据库”。您可以在其中注册浮点数、整数或字符串等变量,人们可以按名称搜索它们,并提取对它们的引用。您还可以注册一个模型(从“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;
};
现在,制作莱康明和大陆发动机:
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();
.
.
.
代码是相当伪的,但我希望它能传达这个想法。一个开发人员可以编写依赖于引擎的代码,但只要它有实现引擎接口的东西,它并不关心它是什么。因此,更新油箱中燃料量的代码与除了 FindModel<>() 函数和他有兴趣使用的纯虚拟 EngineModel 接口之外的所有内容完全解耦。一年后有人可以制造一个新的发动机模型,将它注册到 SimulationDatabase,上面更新燃料的人会自动开始使用它。我实际上是这样做的,因此您可以在运行时将新模型作为插件 (DLL) 加载,一旦它们在 SimulationDatabase 中注册,就可以使用 FindModel<>() 找到它们,即使正在寻找它们的代码在新 DLL 存在几个月前就已编译并构建到 DLL 中。您还可以添加从 SimModel 派生的新接口,在一个 DLL 中实现它们,在另一个 DLL 中搜索它们,一旦加载了两个 DLL,就可以执行 FindModel<>() 来获取模型另一个。即使在构建主应用程序时界面本身甚至不存在。
顺便说一句,RTTI 并不总是跨 DLL 边界工作。因为无论如何我都在使用 Qt,所以我使用qobject_cast
了dynamic_cast
. 每个类都必须从 QObject 继承(并获得 moc'd),但 qobject 元数据始终可用。如果您不关心 DLL,或者您正在使用 RTTI跨 DLL 边界工作的工具链(类型比较基于字符串比较而不是哈希或其他),那么上述所有方法都dynamic_cast
可以正常工作。