Sie sind auf Seite 1von 16

Background

The C++ Programming  Object-oriented programming is often de-


Language ned as the combination of Abstract Data
Types (ADTs) with Inheritance and Dy-
namic Binding
Single and Multiple Inheritance in  Each concept addresses a di erent aspect
of system decomposition:
C++ 1. ADTs decompose systems into two-dimensional
grids of modules
{ Each module has public and private inter-
Douglas C. Schmidt faces

www.cs.wustl.edu/schmidt/ 2. Inheritance decomposes systems into three-dimensional


hierarchies of modules
schmidt@cs.wustl.edu { Inheritance relationships form a \lattice"
Washington University, St. Louis 3. Dynamic binding enhances inheritance
{ e.g., defer implementation decisions until late
in the design phase or even until run-time!
1 2

Data Abstraction vs. Inheritance Motivation for Inheritance


DATA
 Inheritance allows you to write code to
DATA ABSTRACTION
(2
ABSTRACTION
(2 DIMENTIONAL)
DIMENTIONAL)
handle certain cases and allows other de-
velopers to write code that handles more
specialized cases, while your code contin-
ues to work

 Inheritance partitions a system architec-


ture into semi-disjoint components that
are related hierarchically
 Therefore, we may be able to modify and/or
reuse sections of the inheritance hierarchy
without disturbing existing code, e.g.,
{ Change sibling subtree interfaces
INHERITANCE  i.e., a consequence of inheritance
(3 DIMENTIONAL)
{ Change implementation of ancestors
 i.e., a consequence of data abstraction
3 4
Inheritance Overview Visualizing Inheritance
 A type (called a subclass or derived type)
can inherit the characteristics of another
type(s) (called a superclass or base type)
Base
{ The term subclass is equivalent to derived type
Derived
2
 A derived type acts just like the base type, Derived
except for an explicit list of: 1
1. Specializations Derived
5
{ Change implementations without changing
the base class interface
Derived
 Most useful when combined with dynamic Derived 4
binding 3 Derived
6
2. Generalizations/Extensions
{ Add new operations or data to derived classes

5 6

Types of Inheritance Inheritance Trees vs. Inheritance


 Inheritance comes in two forms, depend-
DAGs
ing on number of parents a subclass has
1. Single Inheritance (SI) Base
Derived Derived
{ Only one parent per derived class 1 2
{ Form an inheritance \tree"
{ SI requires a small amount of run-time over- INHERITANCE Derived
head when used with dynamic binding Derived TREE 4
3
{ e.g., Smalltalk, Simula, Object Pascal
2. Multiple Inheritance (MI)
{ More than one parent per derived class Base Base
1
{ Forms an inheritance \Directed Acyclic Graph" Derived 2
(DAG) 1

{ Compared with SI, MI adds additional run-


time overhead (also involving dynamic bind- INHERITANCE
ing) Derived Derived
3 DAG 4
{ e.g., C++, Ei el, Flavors (a LISP dialect)
7 8
Inheritance Bene ts Inheritance Liabilities
1. Increase reuse and software quality
 Programmers reuse the base classes instead of 1. May create deep and/or wide hierarchies
writing new classes that are dicult to understand and navi-
{ Integrates black-box and white-box reuse by gate without class browser tools
allowing extensibility and modi cation with-
out changing existing code
2. May decrease performance slightly
 Using well-tested base classes helps reduce bugs  i.e., when combined with multiple inheritance
in applications that use them and dynamic binding
 Reduce object code size
3. Without dynamic binding, inheritance has
2. Enhance extensibility and comprehensibil- only limited utility
ity  Likewise, dynamic binding is almost totally use-
 Helps support more exible and extensible ar- less without inheritance
chitectures (along with dynamic binding)
{ i.e., supports the open/closed principle
4. Brittle hierarchies, which may impose de-
 Often useful for modeling and classifying hierarchically- pendencies upon ancestor names
related domains
9 10

Key Properties of C++


Inheritance
Inheritance in C++  The base/derived class relationship is ex-
plicitly recognized in C++ by prede ned
standard conversions
 Deriving a class involves an extension to { i.e., a pointer to a derived class may always be
the C++ class declaration syntax assigned to a pointer to a base class that was
inherited publically
 But not vice versa :::

 The class head is modi ed to allow a deriva-


tion list consisting of base classes  When combined with dynamic binding, this
special relationship between inherited class
types promotes a type-secure, polymor-
 e.g., phic style of programming
{ i.e., the programmer need not know the actual
type of a class at compile-time
class Foo f /* ::: g;
class Bar : public Foo f /* g;::: { Note, C++ is not truly polymorphic
class Foo : public Foo, public Bar f /* ::: g;
 i.e., operations are not applicable to objects
that don't contain de nitions of these op-
erations at some point in their inheritance
hierarchy
11 12
Simple Screen Class Subclassing from Screen
 The following code is used as the base
class:  class Screen can be a public base class of
class Window
class Screen f
public:
Screen (int = 8, int = 40, char = ' ');  e.g.,
~Screen (void);
short height (void) const f return this->height ; g
short width (void) const f return this->width ; g class Window : public Screen f
void height (short h) f this->height = h; g public:
void width (short w) f this->width = w; g Window (const Point &, int rows = 24,
Screen &forward (void); int columns = 80,
Screen &up (void); char default char = ' ');
Screen &down (void); void set foreground color (Color &);
Screen &home (void); void set background color (Color &);
Screen &bottom (void); void resize (int height, int width);
Screen &display (void); // :::

Screen &copy (const Screen &); private:


// ::: Point center ;
private: Color foreground ;
short height , width ; Color background ;
char *screen , *cur pos ; // :::

g; g;
13 14

Multiple Levels of Derivation The Screen Inheritance Hierarchy


 A derived class can itself form the basis
for further derivation, e.g.,
Point
class Menu : public Window f
public: Screen
void set label (const char *l); Color
Menu (const Point &, int rows = 24,
int columns = 80,
char default char = ' ');
// :::

private: Window
char *label ; Menu
// :::

g;
 class Menu inherits data and methods from
both Window and Screen
{ i.e., sizeof (Menu) >= sizeof (Window) >= sizeof
(Screen)  Screen/Window/Menu hierarchy

15 16
Variations on a Screen ::: Using the Screen Hierarchy
 e.g.,
ps1 : ps2 : class Screen f public: virtual void dump (ostream &); = 0 g
Screen Screen
class Window : public Screen f
public: virtual void dump (ostream &);
g;
class Menu : public Window f
public: virtual void dump (ostream &);
g;
// stand-alone function
w: void dump image (Screen *s, ostream &o) f
Window
// Some processing omitted
Menu s->dump (o);
// (*s->vptr[1]) (s, o));
g
Screen s; Window w; Menu m;
Bit Vector bv;
 A pointer to a derived class can be as- // OK: Window is a kind of Screen
signed to a pointer to any of its public dump image (&w, cout);
base classes without requiring an explicit // OK: Menu is a kind of Screen
cast: dump image (&m, cout);
// OK: argument types match exactly
dump image (&s, cout);
Menu m; Window &w = m; Screen *ps1 = &w; // Error: Bit Vector is not a kind of Screen!
Screen *ps2 = &m; dump image (&bv, cout);
17 18

Using Inheritance for Specialization Example


Specialization  Inheritance may be used to obtain the fea-
tures of one data type in another closely
 A derived class specializes a base class by related data type
adding new, more speci c state variables
and methods
{ Method use the same interface, even though
 For example, class Date represents an ar-
they are implemented di erently
bitrary Date:
 i.e., \overridden"
class Date f
publicDate
:
(int m, int d, int y);
virtual
//
void print (ostream &s) const;
{ Note, there is an important distinction between private :
:::

overriding, hiding, and overloading ::: int month , day , year ;


g;
 Class Birthday derives from Date, adding
 A variant of this is used in the template a name eld representing the person's birth-
method pattern day, e.g.,
{ i.e., behavior of the base class relies on func- class Birthday : public Date f
publicBirthday
:
tionality supplied by the derived class (const char *n, int m, int d, int y)
: Date (m, d, y), person (strdup (n)) fg
~Birthday (void) f free (person ); g
{ This is directly supported in C++ via abstract virtual
//
void print (ostream &s) const;
base classes and pure virtual functions private :
:::

g;
const char *person ;
19 20
Implementation and Use-case Alternatives to Specialization
 Note that we could also use object com-
 Birthday::print could print the person's name position instead of inheritance for this ex-
as well as the date, e.g., ample, e.g.,
void Birthday::print (ostream &s) const f class Birthday f
s << this->person << " was born on "; public
Date::print (s); Birthday (char *n, int m, int d, int y):
s << "\n"; date (m, d, y), person (n) fg
g // same as before
private:
 e.g., Date date ;
char *person ;
g;
const Date july 4th (7, 4, 1993);
Birthday my birthday ("Douglas C. Schmidt", 7, 18, 1962);
 However, in this case we would not be able
july 4th.print (cerr); to utilize the dynamic binding facilities for
// july 4th, 1993 base classes and derived classes
my birthday.print (cout); { e.g.,
// Douglas C. Schmidt was born on july 18th, 1962
Date *dp = &my birthday; Date *dp = &my birthday;
dp->print (cerr); // ERROR, Birthday is not a subclass of date!
// ??? what gets printed ??? { While this does not necessarily a ect reusabil-
// (*dp->vptr[1])(dp, cerr); ity, it does a ect extensibility
:::

21 22

Extension/Generalization
Using Inheritance for Example
Extension/Generalization
 Using class Vector as a private base class
 Derived classes add state variables and/or for derived class Stack
operations to the properties and opera-
tions associated with the base class class Stack : private Vector f /* ::: */ g;
{ Note, the interface is generally widened!
 In this case, Vector's operator[] may be
{ Data member and method access privileges may reused as an implementation for the Stack
push and pop methods
also be modi ed
{ Note that using private inheritance ensures that
operator[] does not show up in the interface
 Extension/generalization is often used to for class Stack!
faciliate reuse of implementations, rather
than interface
{ However, it is not always necessary or correct  Often, a better approach in this case is
to export interfaces from a base class to de- to use a composition/Has-A rather than
rived classes
a descendant/Is-A relationship :::

23 24
Vector Interface
 Using class Vector as a base class for a
Vector Implementation
derived class such as class Checked Vector
or class Ada Vector  e.g.,
{ One can de ne a Vector class that implements
an unchecked, uninitialized array of elements template <class T>
of type T Vector<T>::Vector (size t s): size (s), buf (new T[s]) fg
template <class T>
 e.g., /* File Vector.h (incomplete wrt ini- Vector<T>::~Vector (void) f delete [] this->buf ; g
tialization and assignment) */
template <class T> size t
// Bare-bones implementation, fast but not safe Vector<T>::size (void) const f return this->size ; g
template <class T>
class Vector f template <class T> T &
public: Vector<T>::operator[] (size t i) f return this->buf [i]; g
Vector (size t s);
~Vector (void); int main (void) f
size t size (void) const; Vector<int> v (10);
T &operator[] (size t index); v[6] = v[5] + 4; // oops, no initial values
int i = v[v.size ()]; // oops, out of range!
private: // destructor automatically called
T *buf ; g
size t size ;
g;
25 26

Bene ts of Inheritance Checked Vector Interface


 Inheritance enables modi cation and/or ex-
tension of ADTs without changing the orig- The following is a subclass of Vector that
inal source code 
allows run-time range checking:
{ e.g., someone may want a variation on the ba-
sic Vector abstraction:
 /* File Checked-Vector.h (incomplete wrt
1. A vector whose bounds are checked on every
reference
initialization and assignment) */
2. Allow vectors to have lower bounds other struct RANGE ERROR f
than 0 "range error" (size t index);
// :::

3. Other vector variants are possible too :::


g;
 e.g., automatically-resizing vectors, initial- template <class T>
ized vectors, etc. class Checked Vector : public Vector<T> f
public:
Checked Vector (size t s);
T &operator[] (size t i) throw (RANGE ERROR);
 This is done by de ning new derived classes // Vector::size () inherited from base class Vector.
that inherit the characteristics of the Vector protected:
base class bool in range (size t i) const;
private:
{ Note that inheritance also allows code to be typedef Vector<T> inherited;
shared g;
27 28
Implementation of
Checked Vector Checked Vector Use-case
 e.g.,  e.g.,
template <class T> bool #include "Checked Vector.h"
Checked Vector<T>::in range (size t i) const f
return i < this->size (); typedef Checked Vector<int> CV INT;
g
template <class T> int foo (int size)
Checked Vector<T>::Checked Vector (size t s) f
: inherited (s) fg try
f
CV INT cv (size);
template <class T> T & int i = cv[cv.size ()]; // Error detected!
Checked Vector<T>::operator[] (size t i) // exception raised
throw (RANGE ERROR) // Call base class destructor
:::

f g
if (this->in range (i)) catch (RANGE ERROR)
return (*(inherited *) this)[i]; f /* */ g
// return BASE::operator[](i);
:::

else g
throw RANGE ERROR (i);
g
29 30

Design Tip
 Note, dealing with parent and base classes Ada Vector Interface
{ It is often useful to write derived classes that
do not encode the names of their direct parent  The following is an Ada Vector example,
class or base class in any of the method bodies where we can have array bounds start at
{ Here's one way to do this systematically: something other than zero
class Base f
public:  /* File ada vector.h (still incomplete wrt
int foo (void); initialization and assignment .) */ :::
g;
class Derived 1 : public Base f #include "vector.h"
typedef Base inherited; // Ada Vectors are also range checked!
public: template <class T>
int foo (void) f inherited::foo (); g class Ada Vector : private Checked Vector<T> f
g; public:
class Derived 2 : public Derived 1 f Ada Vector (size t l, size t h);
typedef Derived 1 inherited;
public: T &operator ()(size t i) throw (RANGE ERROR)
int foo (void) f inherited::size; // explicitly extend visibility
inherited::foo (); private:
g typedef Checked Vector<T> inherited;
g; size t lo bnd ;
{ This scheme obviously doesn't work as trans- g;
parently for multiple inheritance:::

31 32
Ada Vector Use-case
 Example Ada Vector Usage (File main.C)
Ada Vector Implementation #include <iostream.h>
#include <stdlib.h>
 e.g., class Ada Vector (cont'd) #include "ada vector.h"

template <class T> int main (int argc, char *argv[]) f


try f
Ada Vector<T>::Ada Vector (size t lo, size t hi) size t lower = ::atoi (argv[1]);
: inherited (hi , lo + 1), lo bnd (lo) fg size t upper = ::atoi (argv[2]);
Ada Vector<int> ada vec (lower, upper);
template <class T> T &
Ada Vector<T>::operator ()(size t i) ada vec (lower) = 0;
throw (RANGE ERROR) f
if (this->in range (i , this->lo bnd )) for (size t i = lower + 1; i <= ada vec.size (); i++)
return Vector<T>::operator[] (i , this->lo bnd ); ada vec (i) = ada vec (i , 1) + 1;
// or Vector<T> &self = *(Vector<T> *) this;
// self[i , this->lo bnd ];
else // Run-time error, index out of range
throw RANGE ERROR (i); ada vec (upper + 1) = 100;
g
// Vector destructor called when
// ada vec goes out of scope
g
catch (RANGE ERROR) f /* ::: */ g
g
33 34

Memory Layout
 Memory layouts in derived classes are cre- Base Class Constructor
ated by concatenating memory from the
base class(es)
{ e.g., // from the cfront-generated .c le  Constructors are called from the \bottom
up"
struct Vector f
T *buf 6Vector;
size t size 6Vector;  Destructors are called from the \top down"
g;
struct Checked Vector f
T *buf 6Vector;
size t size 6Vector;  e.g.,
g;
struct Ada Vector f /* Vector constructor */
T *buf 6Vector; // Vector struct Vector *
size t size 6Vector; // part ct 6VectorFi (struct Vector * 0this, size t 0s) f
size t lo bnd 10Ada Vector; // Ada Vector if ( 0this jj ( 0this =
g; nw FUi (sizeof (struct Vector))))
(( 0this->size 6Vector = 0s),
 The derived class constructor calls the base ( 0this->buf 6Vector =
constructor in the \base initialization sec- nw FUi ((sizeof (int)) * 0s)));
tion," i.e., return 0this;
g
Ada Vector<T>::Ada Vector (size t lo, size t hi)
: inherited (hi , lo + 1), lo bnd (lo) fg
35 36
Derived Class Constructors
Destructor
 e.g.,
/* Checked Vector constructor */  Note, destructors, constructors, and as-
struct Checked Vector * ct 14Checked VectorFi ( signment operators are not inherited
struct Checked Vector * 0this, size t 0s) f
if ( 0this jj ( 0this =
nw FUi (sizeof (struct Checked Vector))))  However, they may be called automati-
0this = ct 6VectorFi ( 0this, 0s); cally were necessary, e.g.,
return 0this;
g char dt 6VectorFv (
/* Ada Vector constructor */ struct Vector * 0this, int 0 free) f
struct Ada Vector * ct 10Ada VectorFiT1 ( if ( 0this) f
struct Ada Vector * 0this, size t 0lo, size t 0hi) f dl FPv ((char *) 0this->buf 6Vector);
if ( 0this jj ( 0this = if ( 0this)
nw FUi (sizeof (struct Ada Vector)))) if ( 0 free & 1)
if ((( 0this = ct 14Checked VectorFi ( 0this, dl FPv ((char *) 0this);
0hi , 0lo + 1)))) g
0this->lo bnd 10Ada Vector = 0lo; g
return 0this;
g

37 38

Describing Relationships Between


Classes
 Consumer/Composition/Aggregation Has-A vs. Is-A Relationships
{ A class is a consumer of another class when
it makes use of the other class's services, as
de ned in its interface CONSUMER DESCENDANT
RELATIONSHIP RELATIONSHIP
 For example, a Stack implementation could Vector
rely on an array for its implementation and
thus be a consumer of the Array class Stack
{ Consumers are used to describe a Has-A rela- Checked
tionship
Vector
Vector
Ada
 Descendant/Inheritance/Specialization Vector
{ A class is a descendant of one or more other
classes when it is designed as an extension or
specialization of these classes. This is the no-
tion of inheritance
{ Descendants are used to describe an Is-A rela-
tionship
39 40
Interface vs. Implementation The Dangers of Implementation
Inheritance Inheritance
 Class inheritance can be used in two pri-  Using inheritance for reuse may sometimes
mary ways: be a dangerous misuse of the technique
1. Interface inheritance: a method of creating a { Operations that are valid for the base type may
subtype of an existing class for purposes of set- not apply to the derived type at all
ting up dynamic binding, e.g.,
{ Circle is a subclass of Shape (i.e., Is-A rela-  e.g., performing an subscript operation on a
tion) stack is a meaningless and potentially harm-
ful operation
{ A Birthday is a subclass of Date
class Stack : public Vector f
2. Implementation inheritance: a method of reusing // :::

an implementation to create a new class type g;


Stack s;
{ e.g., a class Stack that inherits from class s[10] = 20; // could be big trouble!
Vector. A Stack is not really a subtype or { In C++, the use of a private base class mini-
specialization of Vector mizes the dangers
{ In this case, inheritance makes implementa-  i.e., if a class is derived \private," it is illegal
tion easier, since there is no need to rewrite to assign the address of a derived object to
and debug existing code. a pointer to a base object
 This is called \using inheritance for reuse"
{ On the other hand, a consumer/Has-A relation
 i.e., a pseudo-Has-A relation might be more appropriate :::

41 42

Private vs Public vs Protected Public Derivation


Derivation  e.g.,
Access control speci ers (i.e., public, pri- class A f
 public:
vate, protected) are also meaningful in <public A>
the context of inheritance protected:
<protected A>
private:
<private A>
 In the following examples: g;
{ <: : : .> represents actual (omitted) code
class B : public A f
{ [: : : .] is implicit
public:
[public A]
<public B>
protected:
[protected A]
 Note, all the examples work for both data <protected B>
members and methods private:
<private B>
g;

43 44
Private Derivation Protected Derivation
 e.g.,  e.g.,
class A f class A f
public: public:
<public A> <public A>
private: protected:
<private A> <protected A>
protected: private:
<protected A> <private A>
g; g;
class B : private A f // also class B : A class B : protected A f
public: public:
<public B> <public B>
protected: protected:
<protected B> [protected A]
private: [public A]
[public A] <protected B>
[protected A] private:
<private B> <private B>
g; g;

45 46

Summary of Access Rights


 The following table describes the access
Other Uses of Access Control
rights of inherited methods Speci ers
{ The vertical axis represents the access rights
of the methods of base class  Selectively rede ne visibility of individual
methods from base classes that are de-
{ The horizontal access represents the mode of rived privately
inheritance
class A f
INHERITANCE
ACCESS public:
+-----------+-----+-----+-----+ int f ();
M
E
A
C
| public | pub | pro | pri |
+-----------+-----+-----+-----+
int g ;
M C | protected | pro | pro | pri | :::

B E +-----------+-----+-----+-----+ private:
E S | private | n/a | n/a | n/a | int p ;
R S +-----------+-----+-----+-----+
p p p g;
u r r
b o i
class B : private A f
l t v
public:
A::f; // Make public
protected:
A::g ; // Make protected
 Note that the resulting access is always g;
the most restrictive of the two
47 48
Common Errors with Access
Control Speci ers
General Rules for Access Control
It is an error to \increase" the access of

an inherited method in a derived class Speci ers
{ e.g., you may not say:
class B : private A f  Private methods of the base class are not
// nor protected nor public! accessible to a derived class (unless the
public: derived class is a friend of the base class)
A::p ; // ERROR!
g;
 If the subclass is derived publically then:
 It is also an error to derive publically and
then try to selectively decrease the visibil- 1. Public methods of the base class are accessible
ity of base class methods in the derived to the derived class
class
2. Protected methods of the base class are acces-
{ e.g., you may not say: sible to derived classes and friends only
class B : public A f
private:
A::f; // ERROR!
g;
49 50

Caveats
 Using protected methods weakens the data
hiding mechanism since changes to the Overview of Multiple Inheritance
base class implementation might a ect all
derived classes. e.g.,
in C++
class Vector f
public:
//  C++ allows multiple inheritance
protected:
:::

// allow derived classes direct access { i.e., a class can be simultaneously derived from
T *buf ; two or more base classes
size t size ;
g;
class Ada Vector : public Vector f { e.g.,
public:
T &operator[] (size t i) f class X f /* . */ g;
return this->buf [i];
:::

class Y : public X f /* . */ g;
g
:::

// Note the strong dependency on the name buf


class Z : public X f /* . */ g;
:::

g; class YZ : public Y, public Z f /* . */ g;


:::

{ Derived classes Y, Z, and YZ inherit the data


 However, performance and design reasons members and methods from their respective
may dictate use of the protected access base classes
control speci er
{ Note, inline functions often reduces the need
for these eciency hacks :::

51 52
Multiple Inheritance Illustrated Liabilities of Multiple Inheritance
 A base class may legally appear only once
in a derivation list, e.g.,
Base
NON-VIRTUAL Base { class Two Vector : public Vector, public Vec-
tor // ERROR!
INHERITANCE

 However, a base class may appear multiple


times within a derivation hierarchy
Derived Derived
1 Derived { e.g., class YZ contains two instances of class
12 2 X

 This leads to two problems with multiple


inheritance:
Base
1. It gives rise to a form of method and data
v
member ambiguity
v VIRTUAL { Explicitly quali ed names and additional meth-
INHERITANCE ods are used to resolve this
Derived 2. It also may cause unnecessary duplication of
1 Derived Derived storage
12 2
{ \Virtual base classes" are used to resolve
this
53 54

Overview of Virtual Base Classes


 Virtual base classes allow class designers
Motivation for Virtual Base to specify that a base class will be shared
among derived classes
Classes { No matter how often a virtual base class may
occur in a derivation hierarchy, only \one" shared
instance is generated when an object is instan-
 Consider a user who wants an Init Checked Vector: tiated
class Checked Vector : public virtual Vector  Under the hood, pointers are used in derived
classes that contain virtual base classes
f /* . */ g;
:::

class Init Vector : public virtual Vector


f /* . */ g;
:::
 Understanding and using virtual base classes
class Init Checked Vector : correctly is a non-trivial task since you
public Checked Vector, public Init Vector must plan in advance
f /* ::: . */ g;
{ Also, you must be aware when initializing sub-
classes objects:::

 In this example, the virtual keyword, when


applied to a base class, causes Init Checked Vector
to get one Vector base class instead of two  However, virtual base classes are used to
implement the client and server side of
many implementations of CORBA distributed
objects
55 56
Virtual Base Classes Illustrated

Vector
NON-VIRTUAL Vector Initializing Virtual Base Classes
INHERITANCE
 With C++ you must chose one of two
methods to make constructors work cor-
rectly for virtual base classes:
Checked Init Checked
Vector Checked Vector 1. You need to either supply a constructor in a
Vector virtual base class that takes no arguments (or
has default arguments), e.g.,
Vector::Vector (size t size = 100); // has problems :::

Vector 2. Or, you must make sure the most derived class
calls the constructor for the virtual base class
in its base initialization section, e.g.,
v v
VIRTUAL Init Checked Vector (size t size, const T &init):
INHERITANCE Vector (size), Check Vector (size),
Init Vector (size, init)
Checked Init Checked
Vector Checked Vector
Vector

57 58

Vector Interface Revised


Init Vector Interface
 The following example illustrates templates,
multiple inheritance, and virtual base classes A simple extension to the Vector base class,
in C++ 
that enables automagical vector initializa-
tion
#include <iostream.h>
#include <assert.h> template <class T>
// A simple-minded Vector base class, class Init Vector : public virtual Vector<T>
// no range checking, no initialization. f
template <class T> public:
class Vector Init Vector (size t size, const T &init)
f : Vector<T> (size)
public: f
Vector (size t s): size (s), buf (new T[s]) fg for (size t i = 0; i < this->size (); i++)
T &operator[] (size t i) f return this->buf [i]; g (*this)[i] = init;
size t size (void) const f return this->size ; g g
private: // Inherits subscripting operator and size().
size t size ; g;
T *buf ;
g;

59 60
Init Checked Vector Interface and
Checked Vector Interface Driver
 A simple multiple inheritance example that
 A simple extension to the Vector base class provides for both an initialized and range
that provides range checked subscripting checked Vector
template <class T> template
classpublic <class T>
Init Checked Vector :
class Checked Vector : public virtual Vector<T> Checked Vector<T>, public Init Vector<T> f
f publicInit
:
Checked Vector (size t size, const T &init):
public: Vector<T> (size),
Checked Vector (size t size): Vector<T> (size) fg Init Vector<T> (size, init),
T &operator[] (size t i) throw (RANGE ERROR) f Checked Vector<T> (size) fg
// Inherits Checked Vector::operator[]
if (this->in range (i)) g;
return (*(inherited *) this)[i];  Driver program
else throw RANGE ERROR (i);
g int main
// Inherits inherited::size. try f(int argc, char *argv[]) f
private: size t size = ::atoi (argv[1]);
size t init = ::atoi (argv[2]);
typedef Vector<T> inherited; Init Checked Vector<int> v (size, init);
cout << "vector size = " << v.size ()
<< ", vector contents = ";
bool in range (size t i) const f
return i < this->size (); for (size t i = 0; i < v.size (); i++)
cout << v[i];
g
g; cout << "\n" << ++v[v.size () , 1] << "\n";
catch (RANGE ERROR)
f /* */ g
g
:::

61 62

Multiple Inheritance Ambiguity Summary


 Consider the following:
 Inheritance supports evolutionary, incre-
struct Base 1 f int foo (void); /* . */ g;
:::
mental development of reusable compo-
struct Base 2 f int foo (void); /* . */ g;
nents by specializing and/or extending a
:::

struct Derived : Base 1, Base 2 f /* . */ g;


:::

int main (void) f general interface/implementation


Derived d;
d.foo (); // Error, ambiguous call to foo ()
g  Inheritance adds a new dimension to data
abstraction, e.g.,
 There are two ways to x this problem:
{ Classes (ADTs) support the expression of com-
1. Explicitly qualify the call, by pre xing it with monality where the general aspects of an ap-
the name of the intended base class using the plication are encapsulated in a few base classes
scope resolution operator, e.g.,
d.Base 1::foo (); // or d.Base 2::foo () { Inheritance supports the development of the
application by extension and specialization with-
2. Add a new method foo to class Derived (similar out a ecting existing code :::
to Ei el's renaming concept) e.g.,
struct Derived : Base 1, Base 2 f
int foo (void) f  Without browser support, navigating through
Base 1::foo (); // either, both
g
Base 2::foo (); // or neither complex inheritance hierarchies is dicult :::

g;
63 64

Das könnte Ihnen auch gefallen