CS 3370 Multiple Inheritance in C Multiple Base
CS 3370 Multiple Inheritance in C++
Multiple Base Classes 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
Mixin Classes 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 Able. Test. cpp
Another MI Example Inheriting Implementation “secretly” 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…
Stroustrup Example class Shape {…}; class Common {…}; class Logo : public Shape {…}; class Circle : public Shape, protected Common {…}; class Triangle: public Shape, protected Common {…};
MI Issues 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
IOStreams Hierarchy Redux
Virtual Inheritance 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
Ambiguous Names 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: ambiguous 2. cpp, disambiguate. cpp
Dominance 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
dominance. cpp What if a D object calls f( ) via a pointer?
The Dark Corners How do you initialize a virtual base? With diamond inheritance, there are multiple paths to the shared base Which intermediate class is responsible?
Initializing Virtual Bases 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
virtinit. cpp
Order of Initialization The Final Story (Really!) All virtual bases are initialized before non- virtual 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
virtinit 2. cpp What is the order of initialization for G g; ? (See virtinit 2. cpp)
Inheritance and Copy Semantics 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
- Slides: 19