This page last updated on:
May 16, 2001
Contents and Related Links
CodeWrangler Pages
|
Overview
For many C programmers learning C++, virtual functions
almost seem like magic. Once they are studied and used a little bit, however,
they are usually both easy to understand and easy to design.
Sometimes the rules about declaring and defining virtual functions are
not so easy to remember, though, so this article is going to summarize
and explain a few of these details, specifically signature matching and
inherited virtual function definitions.
Note: This article is not a summary of what virtual functions
are and the basics of how to use them, but rather a clarification of some
of the finer points.
Signature Matching
The first rule to remember is that each derived class that declares a virtual
function must exactly match the signature of the base class virtual function,
including the return type. From Stroustrup, The C++ Programming Language,
2nd Edition:
If a class base contains a virtual function
vf, and a class derived derived from it also contains
a function vf of the same type, then a call of vf for
an object of class derived invokes derived::vf (even
if the access is through a pointer or reference to base). The
derived class function is said to override the base class function.
If the function types are different, however, the functions are considered
different and the virtual mechanism is not invoked. It is an error
for a derived class function to differ from a base class' virtual function
in the return type only.
There has been a relaxation of the return type rule for one case -- a derived
virtual function can return a derived pointer or reference, e.g. a D*
or D&, where the base virtual function returns a base pointer
or reference, a B* or B&, and where D is
a direct or indirect derived class of B. For more explanation
see Stroustrup, The Design and Evolution of C++, section 13.7.
Inherited Virtual Function Definitions
If a derived class omits a virtual function declaration and definition,
the definition is inherited from it's immediate base class. In the past,
I explained that the definition came from the first base class that declared
the virtual function -- in essence the 'root' base class for that particular
virtual function. But after looking up some references and trying some
test code on a couple of compilers, I found that I was wrong. It also makes
sense from the compiler implementation point of view because the compiler
has all the information from the immediate base class to properly construct
the derived class vtable. From Stroustrup, The C++ Programming Language,
2nd Edition:
... A virtual function that has been defined in a base class
need not be defined in a derived class. If it is not, the function defined
for the base class is used in all calls.
Here's some example code and output:
#include <iostream>
using std::cout;
class A {
private:
int x;
public:
virtual void f() { cout << "Inside A::f\n"; }
};
class B : public A {
private:
int y;
public:
virtual void f() { cout << "Inside B::f\n"; }
};
class C : public B {
private:
int z;
public:
// virtual void f() { cout << "Inside C::f\n"; }
};
int main () {
A a_obj;
B b_obj;
C c_obj;
A* a_ptr = &a_obj;
a_ptr->f();
a_ptr = &b_obj;
a_ptr->f();
a_ptr = &c_obj;
a_ptr->f();
return 0;
}
will print:
Inside A::f
Inside B::f
Inside B::f
and not
Inside A::f
Inside B::f
Inside A::f
as I previously thought.
|