Using RTTI with objects obtained from an external library

I work with an external library and have to create an observer template where observers are generated from an object belonging to the library. I do not want to change the base class from the library, and at the same time I have to use a list of references / pointers to this immutable base class. In addition, the library creates a list of objects from which I need to sift through those that are suitable for observation.

The code I wrote is roughly equivalent to this:

#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(); } 

Then I use BaseOfObserver to add "subjective awareness" to my other derived types. Thus, I do not need to repeat the if statement for each specific observer that I want to implement.

Everything seems to be fine, but is this a design error? Is there a better way to create an observer list without the RTTI mechanism and not interfere with library classes?

+6
source share
1 answer

Your problem comes down to the fact that you have a sequence of basic pointers and you want to use only those elements of the sequence that are a specific derived type.

dynamic_cast certainly works, but in this case it is not needed. If you want to store the necessary pointers in a separate container, you will not need to look for them in a container that also contains other pointers.

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

You still have a container with all pointers, copying observer pointers.

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

Alternatively, you can use something like boost :: join from Boost.Range if you want to iterate over all the elements in separate containers without copying.

You can trivially copy observer pointers without dynamic_cast.

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

Of course, if that's all you are going to do, you could use s.observers as your source container for observers in the first place.

As an example, your example memory leak program. Avoid manual memory management to prevent these situations.

0
source

All Articles