You can use another (non-templated) base and a virtual call, like this:
struct VirtualBase {
virtual void call () = 0;
};
template <class Derived>
struct Base : VirtualBase {
virtual void call () override {
static_cast<Derived*>(this)->real_call ();
}
};
struct A : Base<A> {
void real_call () {
cout << "A";
}
};
struct B : Base<B> {
void real_call () {
cout << "B";
}
};
And use it like this:
VirtualBase * a [] = {new A(), new B()};
a[0]->call ();
a[1]->call ();
Note that to have polymorphism, you need to work with pointers or references (which is one of the problems with your code, because you are trying to put instances themselves into an array.)
Also, note the name change between call
and real_call
.
And don't forget to delete
the instances; for example like this:
for (auto e : a) delete e;
or you can use std::unique_ptr<>
, but the initialization of the array will be more verbose.
Update about virtual calls, in response to comments:
If you want to be able to dispatch to different methods determined at runtime, then you have to to use some kind of indirection. You won't be able to let the compiler bake in the call addresses at compile time (which is what happens with ordinary function calls and non-virtual method calls.)
One form of that indirection is using virtual methods; others are using function pointers, or even switch
statements. There are other more exotic and less-used forms of call indirection too (e.g. runtime in-memory patching of addresses, etc.) but they are rarely worth the effort.
In short, if you want to have the flexibility of runtime dispatch, you'll have to pay the price.
Update with another sample: In response to comments on other answers, here's a small sample of CRTP used in conjunction with polymorphism. It's just an example, and not a good one, but I see no reason why they can't be used together.