[英]C++ RTTI Registry Pattern
我有興趣了解有關C ++中RTTI的優點和局限性的更多信息。 假設我有以下情形:
class C {};
class C0 : public C {};
class C1 : public C {};
...
void print(int id, C* c) {
if (id == 0) dynamic_cast<C0 *>(c)->print();
else if (id == 1) dynamic_cast<C0 *>(c)->print();
...
}
是否可以使用注冊表模式來實現上述示例? 例如,使用如下代碼:
map<int, ?> registry;
void print(int id, C* c) {
registry[id](c)->print();
}
僅通過使print
成為虛擬功能就可以很容易地解決此問題。 然后,您可以簡單地擁有:
void print(C* c)
{
c->print();
}
它將對所有派生類做正確的事情。
但是,如果您想使print
保持非虛擬狀態,那么您就會意識到存在一個問題,例如registry[id](c)->print();
可以工作。 映射的值類型是一個編譯時事實,但是您需要行為上的運行時差異。
好吧,我可以想到一種使用虛函數的方法。 您將需要創建一個類作為C
的包裝,其派生版本與從C
派生的類型匹配。 某些模板的使用可能會使它處理起來有些體面。 然后根據指向基礎的指針聲明該映射,但通過派生的包裝器填充該映射。
但是最后,這要復雜得多,並且所帶來的好處並不比僅將print
本身首先虛擬化所帶來的好處多。
雖然使用多態和虛擬方法似乎更合適,但是您可以使用以下方法根據id
注冊和分發
class PrintCaller
{
public:
template <typename T>
std::size_t register_class()
{
m.push_back([](C* c) {
auto* p = dynamic_cast<T*>(c);
if (p) {
p->print();
} else {
throw std::runtime_error("Incorrect type");
}
});
return m.size() - 1;
}
void print(std::size_t id, C* c) const {
if (id < m.size()) {
m[id](c);
} else {
throw std::runtime_error("invalid id");
}
}
private:
std::vector<std::function<void(C*)>> m;
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.