gpt4 book ai didi

c++ - 在没有 RTTI 的情况下使用中央管理器管理不同的类

转载 作者:太空宇宙 更新时间:2023-11-04 12:20:56 24 4
gpt4 key购买 nike

我有一个设计问题困扰了我一段时间,但我找不到好的(在 OOP 意义上)解决方案。语言是 C++,我不断回到 RTTI——这通常被称为糟糕设计的指标。

假设我们有一组不同类型的模块实现为不同的类。每种模块都有一个定义的接口(interface),但实现可能会有所不同。因此,我的第一个想法是为每种模块(例如 IModuleFoo、IModuleBar 等)创建一个接口(interface)(纯抽象)类,并在单独的类中实现。到目前为止一切顺利。

class IModuleFoo {
public:
virtual void doFoo() = 0;
};

class IModuleBar {
public:
virtual void doBar() = 0;
};

另一方面,我们有一组(应用程序)类,它们中的每一个都使用其中的几个模块,但仅通过接口(interface)——甚至模块本身也可能使用其他模块。但是,所有应用程序类都将共享同一个模块池。我的想法是为所有模块创建一个管理器类 (ModuleManager),应用程序类可以查询它们需要的模块类型。可用模块(和具体实现)是在管理器初始化期间设置的,并且可能会随时间变化(但这并不是我的问题的一部分)。

由于不同模块类型的数量很可能 >10 并且可能会随着时间的推移而增加,因此对我来说似乎不适合分别存储对它们的引用(或指针)。此外,管理器可能需要在所有托管模块上调用几个函数。因此,我创建了另一个接口(interface) (IManagedModule),其好处是我现在可以使用 IManagedModules 的容器(列表、集合等)将它们存储在管理器中。

class IManagedModule {
public:
virtual void connect() = 0;
{ ... }
};

结果是,应被管理的模块需要从 IManagedModule 和与其类型相应的接口(interface)继承。

但是当我想到 ModuleManager 时,事情就变得很糟糕。可以假定每种模块类型每次最多有一个实例。因此,如果可以做这样的事情(其中 manager 是 ModuleManager 的实例),一切都会好起来的:

IModuleFoo* pFoo = manager.get(IModuleFoo);

但我很确定它不是。我还考虑了一个基于模板的解决方案,例如:

IModuleFoo* pFoo = manager.get<IModuleFoo>();

这可能行得通,但如果我只有一组 IManagedModules,我不知道如何在管理器中找到正确的模块——当然,这没有使用 RTTI。

一种方法是为 IManagedModule 提供虚拟 getId() 方法,依靠实现为每种模块使用明确的 ID,并自行进行指针转换。但这只是重新发明轮子(即 RTTI),并且需要在实现类中进行大量纪律(提供正确的 ID 等...),这是不可取的。

长话短说 - 问题是这里是否真的没有办法绕过某种 RTTI,在这种情况下 RTTI 甚至可能是一个有效的解决方案,或者是否有更好(更清洁、更安全、...)的设计哪个表现出相同的灵 active (例如应用程序类和模块类之间的松散耦合......)?我错过了什么吗?

最佳答案

听起来您正在寻找类似于 COM 的 QueryInterface 的东西.现在,您不需要完全实现 COM,但基本原则是:您有一个带有虚函数的基类,您可以将一个标识符传递给它,以指定您想要的接口(interface)。虚函数然后查看它是否可以实现该接口(interface),如果可以,则返回一个指向该接口(interface)的指针。

例如:

struct IModuleBase {
// names changed so as not to confuse later programmers with true COM
virtual bool LookupInterface(int InterfaceID, void **interfacePtr) = 0;

// Easy template wrapper
template<typename Interface>
Interface *LookupInterface() {
void *ptr;
if (!LookupInterface(Interface::INTERFACE_ID, &ptr)) return NULL;
return (Interface *)ptr;
}
};

struct IModuleFoo : public IModuleBase {
enum { INTERFACE_ID = 42 };
virtual void foo() = 0;
};

struct SomeModule : public IModuleFoo {
virtual bool LookupInterface(int interface_id, void **pPtr) {
switch (interface_id) {
case IModuleFoo::INTERFACE_ID:
*pPtr = (void*)static_cast<IModuleFoo *>(this);
return true;
default:
return false;
}
}

virtual void foo() { /* ... */ }
};

它有点笨拙,但还算不错,而且如果没有 RTTI,除了像这样的方法之外你别无选择。

关于c++ - 在没有 RTTI 的情况下使用中央管理器管理不同的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5128475/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com