During the class Base's constructor, the object isn't yet a Derived, so if Base::Base() calls a virtual function virt(), the Base::virt() will be invoked, even if Derived::virt() exists.
Similarly, during Base's destructor, the object is no longer a Derived, so when Base::~Base() calls virt(), Base::virt() gets control, not the Derived::virt() override.
You'll quickly see the wisdom of this approach when you imagine the disaster if Derived::virt() touched a member object from class Derived. In particular, if Base::Base() called the virtual function virt(), this rule causes Base::virt() to be invoked. If it weren't for this rule, Derived::virt() would get called before the Derived part of a Derived object is constructed, and Derived::virt() could touch unconstructed member objects from the Derived part of a Derived object. That would be a disaster.
[ Top | Bottom | Previous section | Next section ]
It's legal, but it ain't moral.
Experienced C++ programmers will sometimes redefine a non-virtual function for efficiency (e.g., if the derived class implementation can make better use of the derived class's resources) or to get around the hiding rule. However the client-visible effects must be identical, since non-virtual functions are dispatched based on the static type of the pointer/reference rather than the dynamic type of the pointed-to/referenced object.
[ Top | Bottom | Previous section | Next section ]
It means you're going to die.
Here's the mess you're in: if Base declares a member function f(int), and Derived declares a member function f(float) (same name but different parameter types and/or constness), then the Base f(int) is "hidden" rather than "overloaded" or "overridden" (even if the Base f(int) is virtual).
Here's how you get out of the mess: Derived must have a using declaration of the hidden member function. For example,
If the using syntax isn't supported by your compiler, redefine the hidden Base member function(s), even if they are non-virtual. Normally this re-definition merely calls the hidden Base member function using the :: syntax. E.g.,
[ Top | Bottom | Previous section | Next section ]
If you get a link error of the form "Error: Unresolved or undefined symbols detected: virtual table for class Fred," you probably have an undefined virtual member function in class Fred.
The compiler typically creates a magical data structure called the "virtual table" for classes that have virtual functions (this is how it handles dynamic binding). Normally you don't have to know about it at all. But if you forget to define a virtual function for class Fred, you will sometimes get this linker error.
Here's the nitty gritty: Many compilers put this magical "virtual table" in the compilation unit that defines the first non-inline virtual function in the class. Thus if the first non-inline virtual function in Fred is wilma(), the compiler will put Fred's virtual table in the same compilation unit where it sees Fred::wilma(). Unfortunately if you accidentally forget to define Fred::wilma(), rather than getting a Fred::wilma() is undefined, you may get a "Fred's virtual table is undefined". Sad but true.
[ Top | Bottom | Previous section | Next section ]
E-mail the author
[ C++ FAQ Lite
| Table of contents
| Subject index
| About the author
| ©
| Download your own copy ]
Revised Jul 10, 2000