将RTTI与从外部库派生的对象一起使用

时间:2016-01-11 12:38:40

标签: c++ design-patterns rtti

我正在使用外部库,需要创建一个观察者模式,其中观察者来自属于该库的对象。我不想从库中更改基类,同时我必须使用这个不可更改的基类的引用/指针列表。除此之外,库构造了对象列表,我需要从中筛选出适合观察者的对象。

我写的代码大致相当于:

#include <iostream>
#include <vector>
#include <memory>

// This class is from an external library which I don't want to chagne
class BaseFromLibrary {
  public:
    virtual ~BaseFromLibrary() {}
};

class BaseOfObserver {
  public:
    void notify() { std::cout << "What-ho!\n"; };
};

class Observer : public BaseFromLibrary, public BaseOfObserver {};

class Subject {
  public:
    std::vector<std::shared_ptr<Observer>> observers;
    void notifyObervers() {
        for (auto &o : observers)
            (*o).notify();
    }
};

int main() {
    // This list is constructed by the library and I cannot interfere with that
    // process
    std::vector<std::shared_ptr<BaseFromLibrary>> list{
        std::make_shared<BaseFromLibrary>(), std::make_shared<Observer>()};
    Subject s;

    for (auto &e : list)
        if (std::dynamic_pointer_cast<Observer>(e) != nullptr)
            s.observers.push_back(std::dynamic_pointer_cast<Observer>(e));

    s.notifyObervers();
}

然后我使用BaseOfObserver向我的其他派生类型添加“主题意识”。这样我就不必为我想要实现的每个特定观察者重复一个if语句。

它似乎工作正常,但这是一个设计错误?有没有更好的方法来构建没有RTTI机制的观察者列表并且不干扰库类?

1 个答案:

答案 0 :(得分:0)

你的问题归结为拥有一系列基本指针,并且只想使用特定派生类型的序列元素。

dynamic_cast当然有效,但在这种情况下,没有必要。如果要将所需的指针保存在单独的容器中,则不需要在包含其他指针的容器中查找它们。

std::vector<Observer *> observers {new Observer()};

通过复制观察者指针,你仍然可以拥有一个包含所有指针的容器。

std::vector<BaseFromLibrary *> all {new BaseFromLibrary()};
all.reserve(all.size() + observers.size());
all.insert(all.end(), observers.begin(), observers.end());

或者,如果你想在不复制的情况下迭代单独容器中的所有元素,你可以使用Boost.Range中的boost::join之类的内容。

您可以在没有dynamic_cast的情况下轻松复制观察者指针。

s.observers.insert(observers.begin(), observers.end());

当然,如果您要做的就是这样,那么您可以首先使用s.observers作为观察员的原始容器。

作为旁注,您的示例程序会泄漏内存。避免手动内存管理以防止这些情况。