C++ : Inheritance


PART 11

Q49: What is inheritance?
A: Inheritance is what separates abstract data type (ADT) programming from OOP.
It is not a `dark corner' of C++ by any means.  In fact, everything discussed
so far could be simulated in your garden variety ADT programming language (ex:
Ada, Modula-2, C [with a little work], etc).  Inheritance and the consequent
(subclass) polymorphism are the two big additions which separate a language
like Ada from an object-oriented programming language.



Q50: Ok, ok, but what is inheritance?
A: Human beings abstract things on two dimensions: part-of and kind-of.  We say
that a Ford Taurus is-a-kind-of-a Car, and that a Ford Taurus has parts such as
Engine, Tire, etc.  The part-of hierarchy has been a first class part of
software since the ADT style became relevant, but programmers have had to whip
up their own customized techniques for simulating kind-of (usually in an ad hoc
manner).  Inheritance changes that; it adds `the other' major dimension of
decomposition.

An example of `kind-of decomposition', consider the genus/species biology
charts.  Knowing the internal parts of various fauna and flora is important for
certain applications, but knowing the groupings (kinds, categories) is equally
important.



Q51: How do you express inheritance in C++?
A: By the `: public' syntax:

	class Car : public Vehicle {
	        //---- `: public' is pronounced `is-a-kind-of-a'
	  //...
	};

We state the above relationship in several ways:
 * Car is `a kind of a' Vehicle
 * Car is `derived from' Vehicle
 * Car is `a specialized' Vehicle
 * Car is the `subclass' of Vehicle
 * Vehicle is the `base class' of Car
 * Vehicle is the `superclass' of Car (this not as common in the C++ community)



Q52: What is `incremental programming'?
A: In addition to being an abstraction mechanism that makes is-a-kind-of
relationships explicit, inheritance can also be used as a means of `incremental
programming'.  A derived class inherits all the representation (bits) of its
base class, plus all the base class' mechanism (code).  Another device (virtual
functions, described below) allows derived classes to selectively override some
or all of the base class' mechanism (replace and/or enhance the various
algorithms).

This simple ability is surprisingly powerful: it effectively adds a `third
dimension' to programming.  After becoming fluent in C++, most programmers find
languages like C and Ada to be `flat' (a cute little book, `Flatland', aptly
describes those living in a two dimensional plane, and their disbelief about a
strange third dimension that is somehow neither North, South, East nor West,
but is `Up').

As a trivial example, suppose you have a Linked List that is too slow, and you
wish to cache its length.  You could `open up' the List `class' (or `module'),
and modify it directly (which would certainly be appropriate for such a simple
situation), but suppose the List's physical size is critical, and some
important client cannot afford to add the extra machine word to every List.
Another option would be to textually copy the List module and modify the copy,
but this increases the amount of code that must be maintained, and also
presumes you have access to the internal source code of the List module.  The
OO solution is to realize that a List that caches its length is-a-kind-of-a
List, so we inherit:

	class FastList : public List {
	  int length;	//cache the length here
	public:
	  //override operations so the cache stays `hot'
	};



Q53: Should I pointer-cast from a derived class to its base class?
A: The short answer: yes -- you don't even need the `cast'.

Long answer: a derived class is a specialized version of the base class
(`Derived is-a-kind-of-a Base').  The upward conversion is perfectly safe, and
happens all the time (a ptr to a Derived is in fact pointing to a [specialized
version of a] Base):
    void f(Base* base_ptr);
    void g(Derived* derived_ptr) { f(derived_ptr); }  //perfectly safe; no cast

(note that the answer to this question assumes we're talking about `public'
derivation; see below on `private/protected' inheritance for `the other kind').



Q54: Derived* --> Base* works ok; why doesn't Derived** --> Base** work?
A: A C++ compiler will allow a Derived* to masquerade as a Base*, since a
Derived object is a kind of a Base object.  However passing a Derived** as a
Base** (or otherwise trying to convert a Derived** to a Base**) is (correctly)
flagged as an error.

An array of Deriveds is-NOT-a-kind-of-an array of Bases.  I like to use the
following example in my C++ training sessions:
		`A Bag of Apples is *NOT* a Bag of Fruit'

Suppose a `Bag' could be passed to a function taking a Bag such
as `f(Bag& b)'.  But `f()' can insert *any* kind of Fruit into the Bag.
Imagine the surprise on the caller's face when he gets the Bag back only to
find it has a Banana in it!

Here's another example I use:
	A ParkingLot of Car is-NOT-a-kind-of-a ParkingLot of Vehicle
(otherwise you could pass a ParkingLot* as a ParkingLot*, and the
called fn could park an EighteenWheeler in a ParkingLot designed for Cars!)

These improper things are violations of `contravariance' (that's the scientific
glue that holds OOP together).  C++ enforces contravariance, so you should
trust your compiler at moments like these.  Contravariance is more solid than
our fickle intuition.



Q55: Does array-of-Derived is-NOT-a-kind-of array-of-Base mean arrays are bad?
A: Yes, `arrays are evil' (jest kidd'n :-).

There's a very subtle problem with using raw built-in arrays.  Consider this:

	void f(Base* array_of_Base)
	{
	  array_of_Base[3].memberfn();
	}

	main()
	{
	  Derived array_of_Derived[10];
	  f(array_of_Derived);
	}

This is perfectly type-safe, since a D* is-a B*, but it is horrendously evil,
since Derived might be larger than Base, so the array index in f() not only
isn't type safe, it's not even going to be pointing at a real object!  In
general it'll be pointing somewhere into the innards of some poor D.

The fundamental problem here is that C++ cannot distinguish a ptr-to-a-thing
from a ptr-to-an-array-of-things (witness the required `[]' in `delete[]' when
deleting an array as another example of how these different kinds of ptrs are
actually different).  Naturally C++ `inherited' this feature from C.

This underscores the advantage of using an array-like *class* instead of using
a raw array (the above problem would have been properly trapped as an error if
we had used a `Vec' rather than a `T[]'; ex: you cannot pass a Vec
to `f(Vec& v)').


Inheritance -- virtual functions


Q56: What is a `virtual member function'?
A: A virtual member function is a member fn preceded by the keyword `virtual'.

It has the effect of allowing derived classes to replace the implementation of
the fn.  Furthermore the replacement is always called whenever the object in
question is actually of the derived class.  The impact is that algorithms in
the base class can be replaced in the derived class without affecting the
operation of the base class.  The replacement can be either full or partial,
since the derived class operation can invoke the base class version if desired.

This is discussed further below.



Q57: What is dynamic dispatch?  Static dispatch?
A: In the following discussion, `ptr' means either a pointer or a reference.

When you have a ptr to an object, there are two distinct types in question: the
static type of the ptr, and the dynamic type of the pointed-to object (the
object may actually be of a class that is derived from the class of the ptr).

The `legality' of the call is checked based on the static type of the ptr,
which gives us static type safety (if the type of the ptr can handle the member
fn, certainly the pointed-to object can handle it as well, since the pointed-to
object is of a class that is derived from the ptr's class).

Suppose ptr's type is `List' and the pointed-to object's type is `FastList'.
Suppose the fn `len()' is provided in `List' and overridden in `FastList'.  The
question is: which function should actually be invoked: the function attached
to the pointer's type (`List::len()') or the function attached to the object
itself (`FastList::len()')?

If `len()' is a virtual function, as it would be in the above case, the fn
attached to the object is invoked.  This is called `dynamic binding', since the
actual code being called is determined dynamically (at run time).

On the other hand, if `len()' were non-virtual, the dispatch would be resolved
statically to the fn attached to the ptr's class.



Q58: Can I override a non-virtual fn?
A: Yes but you shouldn't.  The only time you should do this is to get around
the `hiding rule' (see below, and ARM sect.13.1), and the overridden definition
should be textually identical to the base class' version.

The above advice will keep you out of trouble, but it is a bit too strong.
Experienced C++ programmers will sometimes override a non-virtual fn for
efficiency, and will provide an alternate implementation which makes better use
of the derived class' resources.  However the client-visible effects must be
*identical*, since non-virtual fns are dispatched based on the static type of
the ptr/ref rather than the dynamic type of the pointed-to/referenced object.


Q59: Why do I get the warning "Derived::foo(int) hides Base::foo(double)" ?
A: A member function in a derived class will *hide* all member functions of the
same name in the base class, *not* overload them, even if Base::foo(double) is
virtual (see ARM 13.1).  This is done because it was felt that programmers
would, for example, call a_derived.foo(1) and expect Derived::foo(double) to be
called.  If you define any member function with the name `foo' in a derived
class, you must redefine in class Derived all other Base::foo()'s that you wish
to allow access from a Derived object (which generally means all of them; you
should [generally] *not* try to hide inherited public member functions since it
breaks the `conformance' of the derived class with respect to the base class).

   class Base {
   public:
     void foo(int);
   };

   class Derived : public Base {
   public:
     void foo(double);
     void foo(int i) { Base::foo(i); }	// <-- override it with itself
   };


Inheritance -- conformance

Q60: Can I `revoke' or `hide' public member fns inherited from my base class?
A: Never never never do this.  Never.  NEVER!

This is an all-too-common design error.  It usually stems from muddy thinking
(but sometimes it stems from a very difficult design that doesn't seem to yield
anything elegant).



Q61: Is a `Circle' a kind-of an `Ellipse'?
A: Depends on what you claim an Ellipse can do.  Ex: suppose Ellipse has a
`scale(x,y)' method, which is meaningless for Circle.

There are no easy options at this point, but the worst of all possible worlds
is to keep muddling along and hope that no one stubs their toes over the bad
design (if we're serious about reuse, we should fix our mistakes rather than
leave them to a future generation).  If an Ellipse can do something a Circle
can't, a Circle can't be a kind of Ellipse.  Should there be any other
relationship between Circle and Ellipse?  Here are two reasonable options:
 * make Circle and Ellipse completely unrelated classes.
 * derive Circle and Ellipse from a base class representing `Ellipses that
   can't *necessarily* perform an unequal-scale operation'.

In the first case, Ellipse could be derived from class `AsymmetricShape' (with
scale(x,y) being introduced in AsymmetricShape), and Circle should be derived
from `SymmetricShape', which has a scale(factor) member fn.

In the second case, we could create class `Oval' that has only an equal scale
operation, then derive both `Ellipse' and `Circle' from Oval, where Ellipse
--but not Circle-- adds the unequal scale operation (see the `hiding rule' for
a caveat if the same method name `scale' is used for both unequal and equal
scale operations).

In any event, we could create an operation to create an Ellipse whose size et
al are the same as a given Circle, but this would be a constructive operation
(ie: it would create a brand new object, like converting an int to a float, but
unlike passing a reference to a Circle as if it were a ref to an Ellipse).

Example:	class Ellipse : public Oval {
		  //...       ^^^^^^^^^^^^^---- or whatever
		public:
		  Ellipse(const Circle& circle);
		};

Or:		class Circle /*...*/ {
		public:
		  operator Ellipse() const;
		  //...
		};



Q62: Are there other options to the `Circle is/isnot kind-of Ellipse' dilemma?
A: There appear to be 2 other options (but read below for why these are poor):
 * redefine Circle::scale(x,y) to throw an exception or call `abort()'.
 * redefine Circle::scale(x,y) to be a no-op, or to scale both dimensions by
   the average of the parameters (or some other arbitrary value).

Throwing an exception will `surprise' clients.  You claimed that a Circle was
actually a kind of an Ellipse, so they pass a Circle off to `f(Ellipse& e)'.
The author of this function read the contract for Ellipse very carefully, and
scale(x,y) is definitely allowed.  Yet when f() innocently calls e.scale(5,3),
it kills him!  Conclusion: you lied; what you gave them was distinctly *not* an
Ellipse.

In the second case, you'll find it to be very difficult to write a meaningful
semantic specification (a `contract') for Ellipse::scale(x,y).  You'd like to
be able to say it scales the x-axis by `x' and the y-axis by `y', but the best
you can say is `it may do what you expect, or it may do nothing, or it may
scale both x and y even if you asked it to only scale the x (ex: `scale(2,1)').
Since you've diluted the contract into dribble, the client can't rely on any
meaningful behavior, so the whole hierarchy begins to be worthless (it's hard
to convince someone to use an object if you have to shrug your shoulders when
asked what the object does for them).


Inheritance -- access rules


Q63: Why can't I access `private' things in a base class from a derived class?
A: Derived classes do not get access to private members of a base class.  This
effectively `seals off' the derived class from any changes made to the private
members of the base class.



Q64: What's the difference between `public:', `private:', and `protected:'?
A: `Private' is discussed in the previous section, and `public' means `anyone
can access it'.  The third option, `protected', makes a member (either data
member or member fn) accessible to subclasses.

Thus members defined in the `private:' section of class X are accessible only
to the member functions and friends of class X; members defined in the
`public:' section are accessible by everyone; `protected:' members are
accessible by members fns and friends of class X, as well as member fns of
subclasses of X.



Q65: How can I protect subclasses from breaking when I change internal parts?
A: You can make your software more resilient to internal changes by realizing
a class has two distinct interfaces for two distinct sets of clients:
 * its `public:' interface serves unrelated classes
 * its `protected:' interface serves derived classes

A class that is intended to have a long and happy life can hide its physical
bits in its `private:' part, then put `protected:' inline access functions to
these data.  The private bits can change, but if the protected access fns are
stable, subclasses (ie: derived classes) won't break (though they'll need to
be recompiled after a change to the base class).


Inheritance -- constructors and destructors


Q66: Why does base ctor get *base*'s virtual fn instead of the derived version?

Ie: when constructing an obj of class `Derived', Base::Base() invokes `virt()'.
`Derived::virt()' exists (an override of `Base::virt()'), yet `Base::virt()'
gets control rather than the `Derived' version; why?

A: A constructor turns raw bits into a living object.  Until the ctor has
finished, you don't have a complete `object'.  In particular, while the base
class' ctor is working, the object isn't yet a Derived class object, so the
call of the base class' virtual fn defn is correct.

Similarly dtors turn a living object into raw bits (they `blow it to bits'), so
the object is no longer a Derived during Base's dtor.  Therefore the same thing
happens: when Base::~Base() calls `virt()', Base::virt() gets control, not the
Derived::virt() override.  (Think of what would happen if the Derived fn
touched a subobject from the Derived class, and you'll quickly see the wisdom
of the approach).



Q67: Does a derived class dtor need to explicitly call the base destructor?
A: No, you never need to explicitly call a dtor (where `never' means `rarely').
ie: you only have to have an explicit dtor call in rather esoteric situations
such as destroying an object created by the `placement new operator'.  In the
usual case, a derived class' dtor (whether you explicitly define one or not)
automatically invokes the dtors for subobjects and base class(es).  Subobjects
are destroyed immediately after the derived class' destructor body (`{...}'),
and base classes are destroyed immediately after subobjects.  Subobjects are
destroyed from bottom to top in the lexical order they appear within a class,
and base classes from right to left in the order of the base-class-list.


Inheritance -- private and protected inheritance


Q68: How do you express `private inheritance'?
A: When you use `: private' instead of `: public'.  Ex:

	class Foo : private Bar {
	  //...
	};



Q69: How are `private derivation' and `containment' similar? dissimilar?
A: Private derivation can be thought of as a syntactic variant of containment
(has-a).  Ex: it is NOT true that a privately derived is-a-kind-of-a Base:

With private derivation:
	class Car : private Engine {/*...*/};	//a Car is NOT a-kind-of Engine
Similarly:
	class Car { Engine e; /*...*/ };	//normal containment

There are several similarities between these two forms of containment:
 * in both cases there is exactly one Engine subobject contained in a Car
 * in neither case can clients (outsiders) convert a Car* to an Engine*

There are also several distinctions:
 * the second form is needed if you want to contain several subobjects
 * the first form can introduce unnecessary multiple inheritance
 * the first form allows members of Car to convert a Car* to an Engine*
 * the first form allows access to the `protected' members of the base class
 * the first form allows Car to override Engine's virtual functions.

Private inheritance is almost always used for the last item: to gain access
into the `protected:' members of the base class.



Q70: Should I pointer-cast from a `privately' derived class to its base class?
A: The short answer: no, but yes too (better read the long answer!)

From `inside' the privately derived class (ie: in the body of members or
friends of the privately derived class), the relationship to the base class is
known, and the upward conversion from PrivatelyDer* to Base* (or PrivatelyDer&
to Base&) is safe and doesn't need a cast.

From `outside' the privately derived class, the relationship to `Base' is a
`private' decision of `PrivatelyDer', so the conversion requires a cast.
Clients should not exercise this cast, since private derivation is a private
implementation decision of the privately derived class, and the coercion will
fail after the privately derived class privately chooses to change this private
implementation decision.

Bottom line: only a class and its friends have the right to convert a ptr to a
derived class into a ptr to its private base class.  They don't need a cast,
since the relationship with the base class is accessible to them.  No one else
can convert such ptrs without pointer-casts, so no one else should.



Q71: Should I pointer-cast from a `protected' derived class to its base class?
A: Protected inheritance is similar to private inheritance; the answer is `no'.
	class Car : protected Engine {/*...*/};   //protected inheritance

In `private' inheritance, only the class itself (and its friends) can know
about the relation to the base class (the relationship to the base class is a
`private' decision).  In protected inheritance, the relationship with the base
class is a `protected' decision, so *subclasses* of the `protectedly' derived
class can also know about and exploit this relationship.

This is a `for better *and* for worse' situation: future changes to `protected'
decisions have further consequences than changing a private decision (in this
case, the class, its friends, *and* subclasses, sub- sub- classes, etc, all
need to be examined for dependencies upon the relationship to the base class).
However it is also for better, in that subclasses have the ability to exploit
the relationship.

The existence of protected inheritance in C++ is debated in some circles.



Q72: What are the access rules with `private' and `protected' inheritance?
A: Take these classes as examples:
	class B { /*...*/ };
	class D_priv : private   B { /*...*/ };
	class D_prot : protected B { /*...*/ };
	class D_publ : public    B { /*...*/ };
	class Client { B b; /*...*/ };

Public and protected parts of B are `private' in D_priv, and are `protected' in
D_prot.  In D_publ, public parts of B are public (D_prot is-a-kind-of-a B), and
protected parts of B remain protected in D_publ.  Naturally *none* of the
subclasses can access anything that is private in B.  Class `Client' can't
even access the protected parts of B (ie: it's `sealed off').

It is often the case that you want to make some but not all inherited member
functions public in privately/protectedly derived classes.  Ex: to make member
fn B::f(int,char,float) public in D_prot, you would say:
	class D_prot : protected B {
	  //...
	public:
	  B::f;    //note: not  B::f(int,char,float)
	};

There are limitations to this technique (can't distinguish overloaded names,
and you can't make a feature that was `protected' in the base `public' in the
derived).  Where necessary, you can get around these by a call-through fn:
	class D_prot : protected B {
	public:
	  short f(int i, char c, float f) { return B::f(i,c,f); }
	};



Q73: Do most C++ programmers use containment or private inheritance?
A: Short answer: generalizations are always wrong (that's a generalization :-).

The long answer is another generalization: most C++ programmers use regular
containment (also called `composition' or `aggregation') more often than
private inheritance.  The usual reason is that they don't *want* to have access
to the internals of too many other classes.

Private inheritance is not evil; it's just more expensive to maintain, since it
increases the number of classes that have access to `internal' parts of other
classes (coupling).  The `protected' parts of a class are more likely to change
than the `public' parts.