You are not doing anything "wrong". You just hit a special but heavily discussed "feature" of C++. ;-)
Unlike other OO-languages like Java, in C++, all virtual functions called in the constructor are only resolved until the "current" class. so while you are in a
constructor of alpha (including copy constructor), all virtual functions are only resolved until the level of alpha.
The reasoning behind the was, that you should get some kind of guarantee that in a class, every member function is only called after the constructor finished its job (or if its called directly from your own constructor). It was meant to reduce "surprises" when functions suddenly get called without the constructor had a chance to execute first. (Unfortunately its not perfect. There are still some exotic places where these surprises can happen, so in my personal opinion its a wrong decission. But these cases are pretty rare, so maybe the C++ comitee was right after all ;-) ).
Anyway, what this mean is: you can't effectively use virtual functions within a constructor. Sorry.
You could force yourself to always call test() directly after construction. But well.. if you forget... :-(
Or you could provide a function like "clone()" in gamma that will return a copy of itself and then call to test() so you don't forget. And then you use this instead of the copy constructor (and make the copy constructor private):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
class gamma {
...
gamma clone() {}
private:
gamma(const gamma&) {}
};
...
gamma t;
gamma f = clone();
...
gamma gamma::clone()
{
gamma ret(*this);
ret.test(); // <-- now gamma::test get called - obviously. It's not even polymorphic anymore
}
|
If you restrict yourself of creating alpha, beta and gamma objects on the heap using new, the "clone()" can be moved to alpha, made virtual by itself and beta/gamma override it and return a copy of themself on the heap. This is sometimes called "virtual constructor" or "prototype pattern".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
class alpha {
...
virtual alpha* clone() { alpha x=new alpha(*this); x->test(); return x; }
};
class beta : public alpha {
...
virtual beta* clone() { beta x=new beta(*this); x->test(); return x; }
};
class gamma : public beta {
...
virtual gamma* clone() { gamma x=new gamma(*this); x->test(); return x; }
};
...
gamma t;
gamma* f = t.clone();
...
f->access();
...
delete f; // don't forget that now, f is on the heap, so you have to fiddle with deleting it.. :(
|
(Note, that clone() can return pointer to subclasses and still use virtual overriding. That's a feature of C++. So you don't need to cast to anything when you clone gamma from a gamma object directly. ;)
Within the clone() method, you call the test() after you created a copy of yourself. This pattern is common, but does a lot more than you just have in your example (e.g. you can clone gamma-objects from "pointers to alpha" without even knowing about the class "gamma" or "beta".)
Ciao, Imi.