Chapter 21. Virtual Functions

FAQ 21.01 What is the purpose of this chapter?

image

This chapter describes the syntax and semantics of virtual functions, which are the way C++ does dynamic binding. Part II discusses dynamic binding and should be read before this chapter. Dynamic binding is an important concept, and most member functions should be virtual unless there is some compelling performance reason not to make them virtual or unless the programmer intentionally makes the member function a leaf (also known as final) member function (see FAQ 33.10).

FAQ 21.02 What is a virtual member function?

A virtual member function is a member function preceded by the keyword virtual or a member function with the same signature as a virtual function declared in a base class.

In this context, virtual means “overridable.” More specifically, the keyword virtual means that the runtime system automatically invokes the proper member function when it is overridden by a derived class (dynamic binding).

A member function should be made virtual when there will be derived classes that will need to provide their own implementation for the member function. This doesn't require as much clairvoyance as it seems to imply. Normally the virtual functions represent specifically architected places where extensibility is supposed to take place.

Overriding a virtual member function is also straightforward: simply declare the member function in the derived class and define a new implementation for that member function.

FAQ 21.03 How much does it cost to call a virtual function compared to calling a normal function?

In theory, the overhead of dynamic binding is highly dependent on the compiler, operating system, and machine. In practice, almost all compilers do it the same way, and the overhead is very small.

A virtual function call typically costs 10% to 20% more than a nonvirtual function call. The overhead is smaller if there are several parameters, since the dynamic binding part of a virtual function call has constant cost. In practice, the overhead for the linkage of a function call is usually a very small percentage of the cost of the work that gets done, so the cost for a virtual function call is about the same as the cost for a normal function call.

For example, if a system or application spends 5% of its CPU utilization performing the linkage for function calls, and 25% of those calls are converted to virtual function calls, the additional overhead will be 10% of 25% of 5%, or around one-tenth of one percent overall.

If you can afford a normal function call, you can almost always afford a virtual function call.

FAQ 21.04 How does C++ perform static typing while supporting dynamic binding?

Static typing ensures that all declarations, definitions, and uses of a virtual function are consistent while dynamic binding provides the “plumbing” so that the right implementation is called at runtime.

Given a reference (or pointer) to an object, there are two distinct types in question: the static type of the reference and the dynamic type of the referent (that is, the object being referred to). In other words, the object may be an instance of a class that is derived from the class of the reference. Nonvirtual (statically bound) member functions are selected based on the (statically known) type of the reference. Virtual (dynamically bound) member functions are selected based on the (dynamically known) type of the referent.

The legality of the call is checked based on the (statically known) type of the reference or pointer. This is safe because the referent must be “at least as derived as” the type of the reference. This provides the following type safety guarantee: if the class of the reference has the indicated member function, then the class of the referent will as well.

FAQ 21.05 Can destructors be virtual?

Yes, many destructors should be virtual.

Virtual destructors are extremely valuable when some derived classes have specified cleanup code. A practical, easy-to-remember guideline: if a class has any virtual functions, it should have a virtual destructor. The rationale for this is that if a class has no virtual functions, chances are the class designer wasn't planning on the class being used as a base class, so a virtual destructor is unnecessary.

Furthermore, on most compilers there is no additional per-object space cost after the first virtual function, so there is very little reason not to make the destructor virtual if the class already has at least one virtual function.

Note that this guideline is not precise enough for every circumstance, but the precise rule is much harder to remember. Here is the more precise rule: if any derived class (or any data member and/or base class of any derived class, or any base class of any data member of any data member of any derived class, or any data member of any base class of any data member of any derived class and all other recursive combinations of base classes and data members) has (or will ever have) a nontrivial destructor, and if any code anywhere deletes (or will ever delete) that derived class object via a base class pointer, then the base class's destructor needs to be virtual.

FAQ 21.06 What is the purpose of a virtual destructor?

image

A virtual destructor causes the compiler to use dynamic binding when calling the destructor.

A destructor is called whenever an object is deleted, but there are some cases when the user code doesn't know which destructor should be called. For example, in the following situation, while compiling unawareOfDerived(Base*), the compiler doesn't even know that Derived exists, much less that the pointer base may actually be pointing at a Derived.

image

Because Base::~Base() is nonvirtual, only Base::~Base() is executed and the Derived destructor will not run. This could be a very serious error, especially if the Derived destructor is supposed to release some precious resource such as closing a shared file or unlocking a semaphore.

The solution is to put the virtual keyword in front of Base's destructor. Once that is done, the compiler dynamically binds to the destructor, and thus the right destructor is always called:

class Base {
public:
  virtual ~Base();
};

FAQ 21.07 What is a virtual constructor?

image

The virtual keyword cannot be applied to a constructor since a constructor turns raw bits into a living object, and until there is a living object against which to invoke a member function, the member function cannot possibly work correctly. Instead of thinking of constructors as normal member functions on the object, imagine that they are static member functions (see FAQ 16.05) that create objects.

Even though constructors cannot actually be virtual, a very simple idiom can be used to have the same effect. This idiom, called the virtual constructor idiom, allows the creation of an object without specifying the object's exact type. For example, a base class can have a virtual clone() const member function (for creating a new object of the same class and for copying the state of the object, just like the copy constructor would do) or a virtual createSimilar() const member function (for creating a new object of the same class, just as the default constructor would do).

Following is an example of this idiom (the return type is an auto_ptr to help prevent memory leaks and wild pointers; see FAQ 32.01).

image

In Circle::createSimilar() const and Circle::clone() const, the kind-of relationship allows the conversion from a Circle* to a Shape*, then the Shape* is converted to an auto_ptr<Shape> (that is, to a ShapePtr) by the auto_ptr's constructor. In Circle::clone() const, the expression new Circle(*this) calls Circle's copy constructor, since *this has type const Circle& inside a const member function of class Circle.

Users can use clone and/or createSimilar as if they were virtual constructors. An example follows.

image

The output of this program follows.

main() number 1: Circle: radius=42
userCode() number 1: Circle: radius=42
userCode() number 2: Circle: radius=42
userCode() number 3: Circle: radius=0

FAQ 21.08 What syntax should be used when a constructor or destructor calls a virtual function in its object?

image

Use the scope operator, ::.

For example, if a constructor or a destructor of class Base calls a virtual function this->f(), it should call it using Base::f() rather than merely f().

In our experience, this guideline reduces the probability that misunderstandings will introduce subtle defects, since it forces developers to explicitly state what the compiler is obliged to do anyway. In particular, when a constructor invokes a virtual member function that is attached to this object, the language guarantees that the member function that is invoked is the one associated with the class of the constructor, even if the object being constructed will eventually be an object of a derived class that has its own version of the virtual function. An analogous statement can be made for calling a virtual function from a destructor.

image

image

The initialization list of Derived::Derived() calls Base::Base(), even if Base() isn't explicitly specified in the initialization list. During Base::Base(), the object is merely a Base object, even though it will eventually be a Derived object (see FAQ 20.14). This is why Base::f() is called from the body of Base::Base(). During the body of Derived::Derived(), however, Derived::f() is called. The output of this program is as follows.

image

Since developers are often somewhat surprised by this language feature, we recommend that such calls should be explicitly qualified with the scope operator, ::.

FAQ 21.09 Should the scope operator :: be used when invoking virtual member functions?

Only from derived classes, constructors, or destructors.

The purpose of the scope operator is to bypass the dynamic binding mechanism. Because dynamic binding is so important to users, user code should generally avoid using ::. For example, the following prints Base::f() even though the object is really a Derived.

image

FAQ 21.10 What is a pure virtual member function?

A pure virtual member function is a member function that the base class forces derived classes to provide. Normally these member functions have no implementation; but see FAQ 21.11.

A pure virtual member function specifies that a member function will exist on every object of a concrete derived class even though the member function is not (normally) defined in the base class. This is because the syntax for specifying a pure virtual member function forces derived classes to implement the member function if the derived classes intend to be instantiated (that is, if they intend to be concrete).

For example, all objects of classes derived from Shape will have the member function draw(). However, because Shape is an abstract concept, it does not contain enough information to implement draw(). Thus draw() should be a pure virtual member function in Shape.

image

This pure virtual function makes Shape an abstract base class (ABC). Imagine that the “= 0” is like saying “the code for this function is at the NULL pointer.”

Pure virtual member functions allow users to write code against an interface for which there are several functionally different variants. This means that semantically different objects can be passed to a function if these objects are all under the umbrella of the same abstract base class.

FAQ 21.11 Can a pure virtual function be defined in the same class that declares it?

Yes, but new C++ programmers don't usually understand what it means, so this practice should be avoided if the organization rotates developers.

If the goal is to create a member function that will be invoked only by derived classes (such as sharing common code in the abstract base class), create a protected: nonvirtual function instead of using this feature. If the goal is to make something that may be callable from user code, create a distinctly named member function so that users aren't forced to use the scope operator, ::.

The exception to this guideline is a pure virtual destructor in an ABC (see FAQ 21.13).

FAQ 21.12 How should a virtual destructor be defined when it has no code?

It should normally be defined as an inline virtual function. An example follows.

image

The reason Base::~Base() is inline is to avoid an unnecessary function call when Derived::~Derived() automatically calls Base::~Base() (see FAQ 20.05). In this case, Derived::~Derived() is synthesized by the compiler.

FAQ 21.13 Can an ABC have a pure virtual destructor?

Yes, provided the ABC (abstract base class) gives an explicit definition elsewhere. An example follows.

image

Leaving out a definition for Base::~Base() will cause a linker error, because Derived::~Derived() automatically calls Base::~Base() (see FAQ 20.05). In this case, Derived::~Derived() is synthesized by the compiler.

Depending on the compiler, there may be a marginal performance benefit in using a pure virtual destructor with an explicit inline definition versus the inline virtual technique that was described in the previous FAQ. Calls to inline virtual functions can be inlined if the compiler is able to statically bind to the class. However, the compiler may also make an outlined copy of an inline virtual function (for any other cases where it isn't able to statically bind to the call). Although in theory destructors of ABCs don't have these limitations, in practice not all compilers produce optimal code when using the inline virtual technique.

FAQ 21.14 How can the compiler be kept from generating duplicate outlined copies of inline virtual functions?

If a class has one or more virtual functions (either inherited or first-declared in that class), then the class should have at least one non-inline virtual function.

Many compilers use the location of the first non-inline virtual function to determine the source file that will house the class's magical stuff (the virtual table, out-lined copies of inline virtual functions, and so on). If all of the class's virtual functions are defined inline, these compilers may put a static copy of a class's magical stuff in every source file that includes the class's header file.

Note that this advice is fairly sensitive to the compiler. Some compilers won't generate copies of the magical stuff even if all the virtual functions in a class are inline. But even in these compilers, it doesn't cost much to ensure that at least one of the class's virtual functions is non-inline.

FAQ 21.15 Should a class with virtual functions have at least one non-inline virtual function?

It is a good idea.

If the base class has a virtual destructor, the destructor in the derived class will also be virtual, and, unless specified otherwise, will be inline.

The safest bet is to give every derived class at least one non-inline virtual function (assuming the base class has a virtual destructor). To show how subtle this can be, consider this trivial example.

image

Even though no Base or Derived objects are created, the preceding example will fail to link on many systems. The reason is that the only virtual function in class Derived is inline (Derived::~Derived() is a synthesized inline virtual function), so the compiler puts a static copy of Derived::~Derived() into the current source file. Since this static copy of Derived::~Derived() invokes Base::~Base() (see FAQ 20.05) the linker will need a definition of Base::~Base().

Adding a non-inline virtual function to a derived class (for example, thisDoesNothing()) eliminates the linker errors for that derived class, because the compiler puts the (only) copy of the magical stuff into the source file that defines the non-inline virtual function.

image

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset