First, let’s review MI without virtual base classes. This form of MI imposes no new rules. However, if a class inherits two members with the same name but from different classes, you need to use class qualifiers in the derived class to distinguish between the two members. That is, methods in the BadDude
class, derived from Gunslinger
and PokerPlayer
, would use Gunslinger::draw()
and PokerPlayer::draw()
to distinguish between draw()
methods inherited from the two classes. Otherwise, the compiler should complain about ambiguous usage.
If one class inherits from a nonvirtual base class by more than one route, then the class inherits one base-class object for each nonvirtual instance of the base class. In some cases, this may be what you want, but more often, multiple instances of a base class are a problem.
Next, let’s look at MI with virtual base classes. A class becomes a virtual base class when a derived class uses the keyword virtual
when indicating derivation:
class marketing : public virtual reality { ... };
The main change, and the reason for virtual base classes, is that a class that inherits from one or more instances of a virtual base class inherits just one base-class object. Implementing this feature entails other requirements:
• A derived class with an indirect virtual base class should have its constructors invoke the indirect base-class constructors directly, which is illegal for indirect nonvirtual base classes.
• Name ambiguity is resolved via the dominance rule.
As you can see, MI can introduce programming complexities. However, most of these complexities arise when a derived class inherits from the same base class by more than one route. If you avoid that situation, about the only thing you need to watch for is qualifying inherited names when necessary.
Inheritance (public, private, or protected) and containment aren’t always the solution when you want to reuse code. Consider, for example, the Stack
class (see Chapter 10) and the Queue
class (see Chapter 12). These are examples of container classes, which are classes designed to hold other objects or data types. The Stack
class from Chapter 10, for example, stores unsigned long
values. You could just as easily define a stack class for storing double
values or string
objects. The code would be identical except for the type of object stored. However, rather than write new class declarations, it would be nice if you could define a stack in a generic (that is, type-independent) fashion and then provide a specific type as a parameter to the class. Then you could use the same generic code to produce stacks of different kinds of values. In Chapter 10, the Stack
example uses typedef
as a first pass at dealing with this desire. However, that approach has a couple drawbacks. First, you have to edit the header file each time you change the type. Second, you can use the technique to generate just one kind of stack per program. That is, you can’t have a typedef
represent two different types simultaneously, so you can’t use the method to define a stack of int
s and a stack of string
s in the same program.
C++’s class templates provide a better way to generate generic class declarations. (C++ originally did not support templates, and since their introduction, templates have continued to evolve, so it is possible that your compiler, if old, may not support all the features presented here.) Templates provide parameterized types—that is, they are capable of passing a type name as an argument to a recipe for building a class or a function. By feeding the type name int
to a Queue
template, for example, you can get the compiler to construct a Queue
class for queuing int
s.
The C++ library provides several template classes. Earlier in this chapter, you worked with the valarray
template class, and Chapter 4 introduced the vector
and array
template classes. C++’s Standard Template Library (STL), which Chapter 16 discusses in part, provides powerful and flexible template implementations of several container classes. This chapter explores designs of a more elementary nature.
3.147.85.181