First of all, when you say "I don't want don to make a common base class"… Frankly, this is the best you could do. However, if you find it difficult or want really non-intrusive way of using your legacy, I'll understand that: after all, legacy is legacy, some ugliness may be unavoidable.
You certainly should not check up the class every time. Even worse if you check by type comparison: it's slow and not supportable especially if you change inheritance in any way.
I suggest you use facade pattern. You can make a wrapper around your legacy classes. Here is how:
class ABWrapper;
class ClassA {
friend class ABWrapper;
void M() { }
};
class ClassB {
friend class ABWrapper;
void M() { }
};
class ABWrapper {
public:
ABWrapper(ClassA &a) : a(&a), b(0) {}
ABWrapper(ClassB &b) : a(0), b(&b) {}
void M() { a ? a->M(); : b->M(); }
private:
ABWrapper() : a(), b() {} ClassA *const a;
ClassB *const b;
};
Some comments on the code. I suggest you make the interface of your legacy classes private and use friend declaration instead. Even though the common rule of thumb is "don't use friends", dealing with the legacy is a valid excuse for using them. The code is use of passing a class instance by reference to the constructors used with explicitly inaccessible parameter-less constructor guarantees that one of the pointers to the instances of the class is not null.
The wrapper does not control life time if the instances and does not provide destruction. If the implementation where instantiation of the classes
ClassA
and
ClassB
is possible and desirable, destruction of the instances should be done in destructor of the wrapper.
—SA