Multiple Inheritance For - USENIX

Transcription

Multiple Inheritance forC Bjarne Stroustrup AT&T Bell LaboratoriesABSTRACT: Multiple Inheritance is the ability of aclass to have more than one base class (super class).In a language where multiple inheritance is supported a program can be structured as a set ofinheritance lattices instead of (just) as a set ofinheritance trees. This is widely believed to be animportant structuring tool. It is also widelybelieved that multiple inheritance complicates aprogramming language significantly, is hard toimplement, and is expensive to run. I will demonstrate that none ofthese last three conjectures istrue.An earlier version of this paper was presented to the European UNIX Users' Groupconference in Helsinki, May 1987. This paper has been revised to match the multiple inheritance scheme that rvas arrived at afler further experimentation andthought. For more information see Stroustrup [1978; 1989].@Computing Systems,Yol.2. No. 4 . Fall1989 367

I. IntroductionThis paper describes an implementation of a multiple inheritancemechanism for Cr lstroustrup 1986; 1989]. It provides only themost rudimentary explanation of what multiple inheritance is ingeneral and what it can be used for. The particular variation ofthe general concept implemented here is primarily explained interm of this implementation.First a bit of background on multiple inheritance and C implementation technique is presented, then the multiple inheritance scheme implemented for Cr is introduced in three stages:l.The basic scheme for multiple inheritance, the basic strategyfor ambiguity resolution, and the way to implement virtualfunctions.classes included more than once in an inheritance lattice; the programmer has the choice whether amultiply-included base class will result in one or more sub-2. Handling ofobjects being created.3. Details of construction of objects, destruction of objects,and access control.Finally, some of the complexities and overheads introduced bythis multiple inheritance scheme are summarized.2. Multiple InheritanceConsider writing a simulation of a network of computers. Eachnode in the network is represented by an object of class switch,each user or computer by an object ofclass Terminat, and each368 Bjarne Stroustrup

communication line by an object of class tine. One way to monitor the simulation (or a real network of the same structure) wouldbe to display the state of objects of various classes on a screen.Each object to be displayed is represented as an object of classDispl.ayed. Objects of class Displ.ayed are under control of adisplay manager that ensures regular update of a screen and/ordata base. The classes Terminal and switch are derived from aclass task that provides the basic facilities for co-routine stylebehavior. Objects ofclass Task are under control ofa taskmanager (scheduler) that manages the real processor(s).Ideally task and Displ.ayed are classes from a standardlibrary. If you want to display a terminal class Terminal. must bederived from class Displ.ayed. Class Terminat, however, isalready derived from class Task. In a single inheritance language,such as the original version of C [Stroustrup 1986] or Simula67,we have only two ways of solving this problem: deriving Taskfrom oisptayed or deriving Displ.ayed from task. Neither isideal since they both create a dependency between the library versions of two fundamental and independent concepts. Ideally onewould want to be able choose between saying that a Terminal. is atask and a Displ.ayed; that â Line is a oispl.ayed but not a Task;and that a sh,itch is a Task but not a Displ.ayed.The ability to express this using a class hierarchy, that is, toderive a class from more than one base class, is usually referred toas multiple inheritance. Other examples involve the representation of various kinds of windows in a window system [Weinreb &Moon l98l I and the representation of various kinds of processorsand compilers for a multi-machine, multi-environment debugger[Cargill 1986].In general, multiple inheritance allows a user to combineindependent (and not so independent) concepts represented asclasses into a composite concept represented as a derived class. Acommon way of using multiple inheritance is for a designer toprovide sets of base classes with the intention that a user createsnew classes by choosing base classes from each ofthe relevantsets. Thus a programmer creates new concepts using a recipe like"pick an A and/or a 8." In the window example, a user mightspecify a new kind of window by selecting a style of windowinteraction (from the set of interaction base classes) and a style ofMultiple Inheritance lorC 369

appearance (from the set of base classes defining display options).In the debugger example, a programmer would specify a debuggerby choosing a processor and a compiler.Given multiple inheritance and H concepts each of whichmight somehow be combined with one of ü other concepts, weneed t'¡ m classes to represent all the combined concepts. Givenonly single inheritance, we need to replicate information and provide ¡¡ l,l H*¡t classes. Single inheritance handles cases where N 1or M 1. The usefulness of multiple inheritance for avoiding replication hinges on the importance of examples where the values ofI and ¡t are both larger than It appears that examples withN 2 and il z are not uncommon; the window and debuggerexamples described above will typically have both n and ¡l largerthan 2.t.3.C* ImplementationStrategyBefore discussing multiple inheritance and its implementation inC I will first describe the main points in the traditional implementation of the Cr- single inheritance class concept.An object of a Cr- class is represented by a contiguous regionof memory. A pointer to an object of a class points to the firstbyte of that region of memory. The compiler turns a call of amember function into an "ordinaryo'function call with an "extrao'argument; that "extrao' argument is a pointer to the object forwhich the member function is called.Consider a simple class R:rctass A {intl,l.i);In most ofthis paper data hiding issues are ignored to simplify the discussion andshorten the examples. This makes some examples illegal. Changing the word ct.assto struct would make the examples legal, as would adding pubt ic specifrers in theappropriate places.370a;void f( intBjarne Stroustrup

An object of class A will look like thisIinta;INo information is placed in an n except the integer a specifred bythe user. No information relating to (non-virtual) member functions is placed in the object.A call of the member function R: : f :A* Pa;pa- f(2);is transformed by the compiler to an "ordinary function call":f --F1A(pa,2)¡Objects of derived classes are composed by concatenating themembers of the classes involved:ctass A t int a; void f(int); );ctass B : A t int b; void g(int); );ctass C: B { int c; void h(int); };Again, no "housekeeping" information is added, so an object ofclass c looks like this:intintinta;b;c;The compiler n'knows" the position of all members in an object ofa derived class exactly as it does for an object of a simple classand generates the same (optimal) code in both cases.Implementing virtual functions involves a table of functions.Consider:ctass A {int a;,ivirtuaI void f( int);virtuaI void g(int);virtuaI void h(int);Multiple Inheritance forC 37I

int b; void g(int); };int c; void h(int); };class B : A {class C : B {of virtual functions, the vtbt, contains theappropriate functions for a given class and a pointer to it is placedin every object. A class c object looks like this:In thiscase, a tableint a;vptrint b;int c;.vtbl.:IA::fIB::gC::hIA call to a virtual function is transformed into an indirect call bythe compiler. For example,c* pc;Pc- g(2);becomes something like:(*(pc- vptrtII))(Pc,2) ;A multiple inheritance mechanism for Cr must preserve theefficiency and the key features of this implementation scheme.4. Multiple Base ClassesGiven two classes{ . };ctassBt.);ctass Aone can design a third using both as base classes:ctassC:4,8t.);This means that a c is andefine c like this:Ianda B. One mightequivalently2classC:8,4t.];2.372Except for possible side effects in constructors and destructors (access to global variables, input operations, output operations, etc.).Bjarne Stroustrup

4.1 Object LayoutAn object of class c can be laid out as a contiguous object likethis:A partB partC partAccessing a member of classes A, B or c is handled exactly asbefore: the compiler knows the location in the object of eachmember and generates the appropriate code (without spuriousindirections or other overhead).4.2 Member Function CallCalling a member function of R or c is identical to what was donein the single inheritance case. Calling a member function of agiven a c* is slightly more involved:c* p";pc- bf(2);//Il/Ithat bf is a member of Bthat C has no member named bfassumeandexcept the one inherited fromBNaturally, B::bf () expects u s* (to become its ttris pointer). Toprovide it, a constant must be added to pc. This constant,detta(B), is the relative position of the B part of c. This delta isknown to the compiler that transforms the call into:bf --F IB( (B*) ( ( char*)pc deL ta(B) ) ,2) ¡The overhead is one addition of a constant per call of this kind.During the execution of a member function of a the function'sthis pointer points to the a part of c:Multiple Inheritance forCt 373

hêlJe.¡A partB::bf's thisB partCpartNote that there is no space penalty involved in using a secondbase class and that the minimal time penalty is incurred only onceper call.4.3 AmbigaitiesConsider potential ambiguitiesmember i i:if both n ands have a publicctass A t int ii; );ctass B { char* ii; };ctass C: A, B { };In this case c will have two members called i i, A:: i i and B:: i i.Thenc* pc;pc- ii;ll error: A::ii or B::ii?is illegal since it is ambiguous. Such ambiguities can be resolvedby explicit qualifrcation:pc-)A::ii;pc-)B::ii;llllCts A'sCts BrsA similar ambiguity arises if bothRiiiiand s have a function f ( ):class A ( void f(); );class B { int f(); };ctassC:ArB{};c* pc;pc- f()í374Bjarne Stroustrupll error: A::f or B::f?

pc- A::f();pc- B::f();llllCts A'sC.s B'sffAs an alternative to specifying which base class in each call of anf (), one might deñne an f o forc::f o might call the baseclass functions. For example:c.class C: A, B tint f() { A::f(); return B::f(); });c* pc;pc- f()ill C:zf iscattedThis solution usually leads to cleaner programs; it localizes thespecification of the meaning of the name for objects of a derivedclass to the declaration ofthe derived class.4.4 CastingExplicit and implicit casting may also involve modifying a pointervalue with a delta:c*Pc;B* pb;pb (B*)pc;pb pc,Pc Pb;pc (C*)pb;ll pb (B*)((char*)pc del.ta(B))l/ pb (B*)((char*)pc detta(B))I I error: cast neededll pc (C*)((char*)pb-del.ta(B))Casting yields the pointer referring to the appropriate part of thesame object.pc .A partPb.¡B partC partMultiple Inheritanceþr C 37 5

Comparisons are interpreted in the same way:pc pb; ll that is, pc (C*)pbor equivalentty (B*)pc pbll// that is, (B*)((char*)pc del.ta(B)¡ pbor equivalenttyI/pc (C*)((char*)pb-del.ta(B))llNote that in both C and Cr casting has always been anoperator that produced one value given another rather than anoperator that simply reinterpreted a bit pattern. For example, onalmost all machines ( i nt ) .2 causes code to be executed;(f toat)(int).2 is not equal to .2. Introducing multiple inheritance as described here will introduce cases where(char*) (B*)v ! (char*)v for some pointer type B*. Note, however, that when s is a base class of c, {B*)v (Ç*)v v.4.5 Zero Valued PointersPointers with the value zero cause a separate problem in the context of multiple base classes. Consider applying the rulespresented above to a zero-valued pointer:C*pc 0;B*pb 0;if (pb -- 0)pb pc;if (pb 0)I/pb (B*)((char*)pc de[ta(B))The second test would fail since pb would have the value(B*) ( (char*)0 deI ta(B) ).The solution is to elaborate the conversion (casting) operationto test for the pointer-value 0:C*pc 0;B*pb 0;if (pb 0)pb pc,ll pb (pc O)?0:(B*)((char*)pc del.ta(B))if (pb 0)The added complexity and run-time overhead are a test and anincrement.376Bjarne Stroustrup

5. Virtual FunctionsNaturally, member functions may be virtual:ctass A { virtual voidctass B { virtuaI voidctass C : A, B { voidA* pa neÌú C;B* pb ne¡ú C;C* pc ne¡ú C;f(); ];f(); virtuaI void g(); ];f(); };pa- f ( ) ;pb- f ( ) ipc- f ( ) iAll these calls will invoke c: : f ( ¡. This follows directly from thedefinition of virtual. since class c is derived from class n andfrom class e.5.1 ImplementationOn entry to c: : f , the th i s pointer must point to the beginning ofc object (and not to the e part). However, it is not in generalknown at compile time that the s pointed to by pb is part of a cso the compiler cannot subtract the constant del.ta(B). Consequently del.ta(B) must be stored so that it can be found at runtime. Since it is only used when calling a virtual function theobvious place to store it is in the table of virtual functions (vtbt).For reasons that will be explained below the delta is stored witheach function in the vtbl. so that a vtbl. entry will be of theform:3thestruct vtb[-entry {);voidint(*fct) ( );delta;An object of class c will look like this:3.The AT&T Cl 2.0 implementation uses three frelds in this structure, but only thetwo shown here are used by the virtual function call mechanism; see Lippman &Stroustrup [ 1988].Multipte Inheritanceþr C 377

vPtr .A partvptr .B partvtbl.:I C::f 0 vtbl.:I C::f -del,ta(B)0I B::s IIC partpb- f()ill call of C::f:// register vtb[-entry* vt &pb-)vtbttindex(f)t;I I çvt. fct) ((B*)((char*)pb vt- detta))Note that the object pointer may have to be adjusted to point tothe correct sub-object before looking for the member pointing tothe vtbl. Note also that each combination of base class andderived class has its own vtbl. For example, the vtbt for s in cis different from the vtbl. of a separately allocated a. Thisimplies that in general an object of a derived class needs a vtbl,for each base class plus one for the derived class. However, aswith single inheritance, a derived class can share a vtbt with itsfirst base so that in the example above only two vtbl.s are used foran object of type c (one for n in c combined with c's own plusonefor e inc).Using an int as the type of a stored delta limits the size of asingle object; that might not be a bad thing.5.2 AmbigaitiesThe following demonstrates a problem:ctassctassctassC* pcA { virtual void f()i ]iB { virtual void f(); ];C : A, B { void f()i }i new C;pc- f ( ) i378Bjarne Stroustrup

pc- A::f();pc- B::f();Explicit qualification "suppresses" virtuat so the last twocalls really invoke the base class functions. Is this a problem?Usually, no. Either c has an f and there is no need to useexplicit qualification or c has no f ¡ and the explicit qualificationis necessary and correct. Trouble can occur when a function f tis added to c in a program that already contains explicitlyqualiûed names. In the latter case one could wonder why someone would want to both declare a function virtual and also call itusing explicit qualifrcation. If f ( ) is virtual, adding an f ( ) to thederived class is clearly the correct way of resolving the ambiguity.The case where no c: : t is declared cannot be handled byresolving ambiguities at the point of call. Consider:ctass A { virtual voidctass B { virtual voidclass C : A, B { }iC* pc new C;pc- f ( ) iA* pa pc;pa- f ( ) if(); ];f(); ];ll error: C::fneeded// ambiguous/l inpLicit conversion of C* to A*l/ not ambiguous: caIts A::f();The potential ambiguity in a call of t I is detected at the pointwhere the virtual function tables for R and s in c are constructed.In other words, the declaration of C above is illegal because itwould allow calls, such as pa- f t, which are unambiguous onlybecause type information has been "lost" through an implicitcoercion; a call of t c I for an object of type c is ambiguous.6. Multiple InclusionsA class can have any number of base classes. For example,ctassA:81,82,83,84,85,Bó{ . };It illegal to specify the same class twice in a list of base classes.For example,ctass A:B, B {. }; //errorMultiple Inheritanceþr C 379

The reason for this restriction is that every access to a B memberwould be ambiguous and therefore illegal; this restriction alsosimplifres the compiler.6.1 Multiple sub-objectsA class may be included more than once as a base class. Forexample:ctassLt.);ctass A : L t . );class B : L { . };ctass C : A , B { . };In such cases multiple objects of the base class are part of anobject of the derived class. For example, an object of class c hastwo L's: one for ¡ and one for g:L part(ofA)A partL part(ofB)B partC partThis can even be useful. Think of I as a link class for a Simulastyle linked list. In this case a c can be on both the list of Es andthe list of ss.380 Bjarne Stroustrup

6.2 NamingAssume that class I in the example above has a member m. Howcould a function c: : f refer to t: : m? The obvious answer is "byexplicit qualifr cation" :void C::f() { A::m B::m; }This will work nicely provided neither A nor e has a member m(except the one they inherited from L). Ifnecessary, thequalification syntax of C r could be extended to allow the moreexplicit:void C::f() { A::L::m B::L::m; }6.3 CastingConsider the example above again. The fact that there are twocopies of I makes casting (both explicit and implicit) between l-*and c* ambiguous, and consequently illegal:C* pc new C;L* p[ pc;pt (L*)pc;pt (L*)(A*)pc;pc pt;pc (L*)pt ipc (C*)(A*)pt illI/lll/llllerror: ambiguouserror: sti l. I ambiguousThe L in Crs Aerror: ambiguouserror: stitI ambiguousThe C containing A's Lexpect this to be a problem. The place where this willsurface is in cases where ns (or as) are handled by functionsexpecting an L; in these cases a c will not be acceptable despite ac being an A:I don'texternf(L*);l/somestandard functionA aa;C cc;f(&aa);f(&cc);f((A*)&cc);IIII fineI error:I fineambiguousCasting is used for explicit disambiguation.Multiple Inheritance forCt 381

7. Virtual BaseClasses\ù/hen a class c has two base classes R and s these two baseclasses give rise to separate sub-objects that do not relate to eachother in ways different from any other ¡ and e objects. I call thisindependent multiple inheritance. However, many proposed usesof multiple inheritance assume a dependence among base classes(for example, the style of providing a selection of features for awindow described in 2). Such dependencies can be expressed interms of an object shared between the various derived classes. Inother words, there must be a way of specifying that a base classmust give rise to only one object in the final derived class even ifit is mentioned as a base class several times. To distinguish thisusage from independent multiple inheritance such base classes arespecified to be virtual:ctass Atlctass Btlctass Ct,: virtual h, t . ];: virtuaI t., t . ];: Ahl , Bt, { . };A single object of class w is to be shared between nw and Bu,; thatis, only one t, object must be included in cw as the result of deriving cw from Rw and sr,,. Except for giving rise to a unique objectin a derived class, a virtuat. base class behaves exactly like anon-virtual base class.The "virtualness" of u is a property of the derivation specifredby lw and sw and not a property of t.t itself. Every virtuat basein an inheritance DAG refers to the same object.A class may be both a normal and a virtual base in an inheritance };ctassD:L,C{.};A););o object will have two sub-objects of class L, one virtual andone "normal."Virtual base classes provide a way of sharing informationwithin an inheritance DAG without pushing the shared information to an ultimate base class. virtual bases can therefore be usedto improve locality of reference. Another way of viewing classes382Bjarne Stroustrup

derived from a common virtual base is as alternative and composable interfaces to the virtual base.7.1 RepresentationThe object representing a virtual base class u object cannot beplaced in a frxed position relative to both ¡w and st, in all objects.Consequently, a pointer to ll must be stored in all objects directlyaccessing the u object to allow access independently ofits relativeposition. For example:Ab'l* paul new Alú; new Bl'f;Cl'l* pcw new Clllg¡*pbwpaH . - At',parttl partIlvl .IIpbt{ . BLJhlpartpartIlvl .IIMultipte Inheritance forC 383

pctJ . All partBhrlpartvCll partLlpartl IIA class can have an arbitrary number of virtual base classes.One can cast from a derived class to a virtual base class, butnot from a virtual base class to a derived class. The formerinvolves following the virtual base pointer; the latter cannot bedone given the information available at run time. Storing a"back-pointer" to the enclosing object(s) is non-trivial in generaland was considered unsuitable for Cr as was the alternative strategy of dynamically keeping track of the objects "for which" agiven member function invocation operates. The uses of such aback-pointer mechanism did not seem to warrant the addedimplementation complexity, the extra space required in objects,and the added run-time cost of initialization.The information necessary to cast from a virtual base class toa derived class is part of what is needed to perform a virtual callof a function declared in the virtual base and overridden by thederived class. The absence of the back-pointer can thus be compensated for by defining and calling appropriate virtual functions:cIass B t virtuaI void f();ctass D : virtual B { voidvoid g(B* p)'),,instead. ];f(); . };of casting ¡,t to a D* here cal. l. f()Since explicit casting is often best avoided this technique actuallyleads to better code in many cases.384Bjarne Stroustrup

7.2 Virtual FunctionsConsider:ctass I'l ();h()ik()i);ctass AUI : virtuat tl { void g(); . };ctass Bll : virtual H { void f(); . };ctass CLJ : Ahl , Bh, { void h(); . };GLj* pc¡¡ new Cllipcu-)f()ipcw- g();pcw- h();((Alt*)pcw)- fAcwllllllI/();Bw:.zf('tAtl g(,C\l zh()Bht::f ();object might look like this:. IvlAl'lpart. IvlBL,partCl'lpart. lvptrIIIhl.partvtbt:¡lII BU::fde L ta ( Bhl) -de tCt'l: : h-de L ta (l'l)-de t ta (t'l)ül::k0AH::sta(ül)In general, the delta stored with a function pointer in a vtbl' isthe delta of the class defrning the function minus the delta of theclass for which the vtbl, is constructed.Multiple Inheritanceþr C 385

If w has a virtual function f that is re-defrned in both nw andbut notin cu, an ambiguityresults. Such ambiguities are easilypointdetected at thewhere cr.t's vtbt is constructed.The rule for detecting ambiguities in a class lattice, or moreprecisely a directed acyclic graph (DAG) of classes, is that there allre-defrnitions of a virtual function from a virtual base class mustoccur on a single path through the DAG. The example above canbe drawn as a DAG like this:Bt,IIIIAh,{s}Br{tf}IIINote that a call "up" through one path of the DAG to a virtualfunction may result in the call of a function (re-defrned) inanother path (as happened in the call (Aw*)pcw)- tcl in theexample above).7.3 Using virtual basesProgramming with virtual bases is trickier than programming withnon-virtual bases. The problem is to avoid multiple calls of afunction in a virtual class when that is not desired. Here is a possible style:ctass' Í, .-.-f() tprotec ted:publ.ic:mystuff )f() { -f(); });Each class provides a protected function doing "its own stufl"-f ( ), for use by derived classes and a public function f I as theinterface for use by the "general public."386Bjarne Stroustrup

ctass A: pubtic virtuatu .protected:-f() {pubLic:);u.mYI'l{stuff }f() { -f(); }l::-f(); }.uA derived class f ( I does its "own stuff' by calling -f ( ) and itsbase classes' "owr stuff' by calling their -f ( )s.: publ.ic virtuaI l'l {il .protec ted:-f() { my stuff }ll "'pubtic:f() { -f(); w::-f(); }t/ .);cIass BIn particular, this style enables a class that is (indirectly) derivedtwice from a class w to call td: : f ( ) once only:class C : publ.ic A, public B, public virtuat ]l {u .protected:-f() tpubt i c:);u .mystuff )f() t -f(); A::-f(); B::-f(); U::-f(); )u ,.-Method combination schemes, such as the ones found in Lispsystems with multiple inheritance, rryere considered as a rvay ofreducing the amount of code a programmer needed to write incases like the one above. However, none of these schemesappeared to be sufficiently simple, general, and efficient enough towarrant the complexity it would add to Cr .Multiple Inheritanceþr C 387

8. Constructors and DestructorsConstructors for base classes are called before the constructor fortheir derived class. Destructors for base classes are called afterthe destructor for their derived class. Destructors are called in thereverse order of their declaration.Arguments to base class constructors can be specifred like this:ctassA{A(int);}ictassBtB(int);)ictass C: A, virtual B {C(int a, int b) : A(a), B(b) t.);)Constructors are executed in the order they appear in the listof bases except that a virtual base is always constructed beforeclasses derived from it.A virtual base is always constructed (once only) by its "mostderived" class. For example:ctass V { V(); V(int); . };ctass A: virtual V { A(); A(int); .cIass B: virtuaI V { B(); B(int), .ctass C : A, B { C(); C(int), . t,v v(1);a(2);b(3)ìc c(4) iABll//l/l/}it,use v(int)use v(int)use V()use v()9. Access ControlThe examples above ignore access control considerations. A baseclass may be pubtic or private. In addition, it may be virtuat.For example:class388DBjarne Stroustrup: 81ll private (by defautt),non-virtua[ (by def aul.t)/I, virtuaI 82 // private (by defaul.t), virtuaI, pubtic 83 ll public, non-virtual//(by defauLt)

);, pubtic virtual.il .84 {Note that a access or virtual. specifrer applies to a single baseclass only. For example,ctass C:publ.ic A, B t . );declares a public base R and a private base s.A virtual class that is accessible through a path is accessibleeven if other paths to it use private derivation.10. OverheadsThe overhead in using this scheme is:l.One subtraction of a constant for each use of a member in abase class that is included as the second or subsequent base.2. One word per function in each vtbt (to hold the delta).3. One memory reference and one subtraction for each call ofa virtual function.4. One memory reference and one subtraction for access of abase class member of a virtual base class.Note that overheads l. and 4. are only incurred where multipleinheritance is actually used, but overheads 2. and 3. are incurredfor each class with virtual functions and for each virtual functioncall even when multiple inheritance is not used. Overheads l. and4. are only incurred when members of a second or subsequentbase are accessed "from the outside"; a member function of a virtual base class does not incur special overheads when accessingmembers of its class.This implies that except for 2. and 3. you pay only for whatyou actually use; 2. and 3. impose a minor overhead on the virtualfunction mechanism even where only single inheritance is used.This latter overhead could be avoided by using an alternativeimplementation of multiple inheritance, but I don't know of suchan implementation that is also faster in the multiple inheritancecase and as portable as the scheme described here.Multiple Inheritanceþr C 389

Fortunately, these overheads are not significant. The time,space, and complexity overheads imposed on the compiler toimplement multiple inheritance are not noticeable to the user.11.But is it Simple toUse?What makes a language facility hard to use?l.Lots of rules.2. Subtle differences between rules.3. Inability to automatically detect common errors.4. Lack of generality.5. Defrciencies.The first two cases lead to difficulty of learning and remembering,causing bugs due to misuse and misunderstanding. The last twocases cause bugs and confusion as the programmer tries to circumvent the rules and "simulateo'missing features. Case 3. causesfrustration as the programmer discovers mistakes the hard way.The multiple inheritance scheme presented here provides twoways of extending a class's name space:l.A base class.2. A virtual base class.These are two ways of creating/specifying a new class rather thanways of creating two different kinds of classes. The rules for usingthe resulting classes do not depend on how the name space wasextended:l.Ambiguities are illegal.2. Rules foruse of members are what they werefor singleinheritance.3. Visibility rules are what they were for single inheritance.4. lnitialization rules are what they were for single inheritance.Violations of these rules are detected by the compiler.390Bjarne Stroustrup

In other words, the multiple inheritance scheme is only morecomplicated to use than the existing single inheritance scheme inthatl.You can extend a class's name space more than once (withmore than one base class).2. You can extend a class's name space in two ways ratherthan in only one way.In addition, care must be taken to take the sharing intoaccount when programming member functions of classes with virtual base classes; see section 7 above.This appears minimal and constitutes an attempt to provide aformal and (comparatively) safe set of mechanisms for observedpractices and needs. I think that the scheme described here is "assimple as possible, but no simpler."A potential source of problems exists in the absence of o'system provided back-pointers" from a virtual base class to itsenclosing object.In som

Multiple Inheritance for C Bjarne Stroustrup AT&T Bell Laboratories ABSTRACT: Multiple Inheritance is the ability of a class to have more than one base class (super class). In a language where multiple inheritance is sup- ported a program can be structured as a set of inheritance lattices instead of (just) as a set of inheritance trees. This is widely believed to be an