FAQ 20.13 When the constructor of a base class calls a virtual function, why isn t the override called?

FAQ 20.13 When the constructor of a base class calls a virtual function, why isn't the override called?

C++ is ensuring that member objects are initialized before they are used.

Objects of a derived class mature during construction. While the base class's constructor is executing, the object is merely a base class object. Later, when the derived class's constructor begins executing, the object matures into a derived class object. If a virtual function is invoked while the object is still immature, the immature version of the virtual function is called. It may sound confusing, but it's the only sensible way to do it without having across-the-board reference semantics.

For example, suppose class Derived overrides an inherited virtual function f(), and Base::Base() calls f(). Since the object is a Base during the execution of Base::Base(), Base::f() is invoked. If C++ allowed Base::Base() to call Derived::f(), Derived::f() might invoke member functions on a member object that had not yet been constructed!

 #include <iostream> using namespace std; class MemberObject { public:   MemberObject()     throw();   void doSomething() throw(); }; MemberObject::MemberObject()     throw() { cout << "MemberObject ctor\n"; } void MemberObject::doSomething() throw() { cout << "MemberObject used\n"; } class Base { public:   Base()           throw();   virtual void f() throw(); }; Base::Base()   throw() { cout << "Base ctor\n"; f(); } void Base::f() throw() { cout << "Base::f()\n"; } class Derived : public Base { public:   Derived()        throw();   virtual void f() throw(); protected:   MemberObject m_; }; Derived::Derived() throw() : Base(), m_() { cout << "Derived ctor\n"; } void Derived::f()  throw() { cout << "Derived::f()\n"; m_.doSomething(); } int main() {   Derived d;   cout << "====\n";   d.f(); } 

The output of this program follows.

 Base ctor Base::f() MemberObject ctor Derived ctor ==== Derived::f() MemberObject used 

If C++ allowed Base::Base() to call Derived::f(), m_.fred() would be called before m_ was constructed.

C++ programmers need to be aware that Java does things quite differently, and therefore Java has a completely different problem. In Java, the derived class's override does get called when the base class's constructor invokes a method. This means that the derived class's override cannot assume that the derived class's constructor was run before the member function is called, so member variables that the derived class's constructor sets to some non-null state may in fact still be null when the override is called.

Neither the C++ approach nor the Java approach is a clear winner in terms of being intuitive and lacking surprises. So the most important point is to understand the differences and be prepared for a learning curve when moving between the two languages.



C++ FAQs
C Programming FAQs: Frequently Asked Questions
ISBN: 0201845199
EAN: 2147483647
Year: 2005
Pages: 566
Authors: Steve Summit

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net