簡體   English   中英

C ++ RTTI注冊表模式

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM