Multiple Inheritance in C++
Download
Report
Transcript Multiple Inheritance in C++
CS 3370
C++ allows multiple implementation
inheritance
Handy for multiple “is-a” situations
Handy for reusing implementation without “is-a”
Leads to C++’s Darkest Corner (IMHO)
Inheritance “hierarchy” becomes a DAG
Ambiguities galore!
Complicated rules
Invented with Common Lisp (“Flavors”)
Clients inherit implementation to gain a capability
Printable, Storable, etc.
Mixin classes are often abstract
Provides most but not all of feature
You override virtual function(s) to complete the feature
A Mixin that itself happens to derive from another class
should do so via virtual inheritance (described later)
See AbleTest.cpp
Suppose we have the proverbial Shape
hierarchy
Circle, Triangle, etc.
If there is common code to all shapes, you
can put it in Shape
If it is common to only some, keep it a secret
Don’t have it derive from Shape
See next slide…
class Shape {…};
class Common {…};
class Logo : public Shape {…};
class Circle : public Shape,
protected Common {…};
class Triangle: public Shape,
protected Common {…};
A derived object has a subobject for each base
class
data duplication!
Name clashes possible
Possible duplicate data via “diamond”
inheritance
Examples: upcast.cpp, delta.cpp,
ambiguous.cpp
Base1
Base1
Base2
Base3
Derived
The derived class holds a pointer to the base
subobject
It is not inherited by value
Only one subobject exists in the complete object
Therefore, there is no ambiguity in casting to
the top-level class
Base1
Base2
Base3
Derived
There must be no ambiguity in name lookup
If multiple base classes contain the same
member names, you have a problem
If a member function, you can override it and do
the Right Thing
If a data member, you must use “::”
And they must still be accessible
Examples: ambiguous2.cpp, disambiguate.cpp
A fancy name for the way virtual functions
work
The “most-derived” binding applies
B::f dominates A::f if A is a (direct or indirect) base
class of B
Non-virtual functions work the same way for
consistency
A{f}
B{f}
C
D
What if a D object calls f( ) via a pointer?
How do you initialize a virtual base?
With diamond inheritance, there are multiple
paths to the shared base
Which intermediate class is responsible?
None!
There’s no criterion for choosing
It is always initialized, therefore, by the most
derived class
Other initializations are ignored, but must be
supplied by every derived concrete class
This makes for weird, but necessary code
See next slides
Top
Right
Left
Bottom
All virtual bases are initialized before nonvirtual bases
No matter where they are
In top-down-left-to-right order
Subobjects are never initialized twice
So the compiler has a lot of work to do to keep
track of things
A
B
C
virtual
virtual
virtual
virtual
E
F
G
What is the order of
initialization for G g; ?
(See virtinit2.cpp)
D
Affects copy constructors and assignment operators
Copy constructors work okay
Most-derived class must still take care of virtual base,
similar to initialization example
Assignment operators are different!
They are not inherited
You must control all sub-assignments explicitly!
Examples: assignment.cpp, virtassign*.cpp