fall stroustrup

29
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 important structuring tool. It is also widely believed that multiple inheritance complicates a programming language significantly, is hard to implement, and is expensive to run. I will demon- strate that none ofthese last three conjectures is true. An earlier version of this paper was presented to the European UNIX Users' Group conference in Helsinki, May 1987. This paper has been revised to match the multi- ple inheritance scheme that rvas arrived at afler further experimentation and thought. For more information see Stroustrup [1978; 1989]. @ Computing Systems,Yol.2. No. 4 . Fall 1989 367

Upload: virabhadrasakro

Post on 17-Aug-2015

238 views

Category:

Documents


0 download

DESCRIPTION

n

TRANSCRIPT

MultipleInheritance for C+Bjarne StroustrupAT&T BellLaboratoriesABSTRACT:MultipleInheritanceis the abilityof aclass to havemorethan one baseclass(superclass).In a language wheremultipleinheritanceis sup-ported a program can be structuredas a set ofinheritancelatticesinstead of (just)as a set ofinheritancetrees. This is widely believed to be animportant structuring tool. It is also widelybelieved thatmultiple inheritancecomplicatesaprogramminglanguage significantly,is hard toimplement,and is expensiveto run. I will demon-stratethatnone oftheselastthree conjecturesistrue.An earlierversionof this paperwas presentedto the European UNIX Users'Groupconferencein Helsinki,May1987.This paperhasbeenrevised to matchthemulti-ple inheritanceschemethat rvas arrivedat aflerfurtherexperimentationandthought. For moreinformationseeStroustrup [1978; 1989].@ ComputingSystems,Yol.2.No.4 . Fall 1989 367I. IntroductionThis paper describes an implementationof a multipleinheritancemechanism for Cr+ lstroustrup 1986; 1989]. It provides only themostrudimentaryexplanationof what multipleinheritanceis ingeneralandwhat it can be usedfor. Theparticularvariationofthe generalconcept implementedhereis primarilyexplainedintermof this implementation.Firsta bit of backgroundon multiple inheritanceand C++implementationtechniqueis presented,then the multipleinheri-tance schemeimplementedfor Cr+ is introducedin three stages:l. The basicschemefor multiple inheritance,the basicstrategyfor ambiguity resolution, and the wayto implement virtualfunctions.2. Handling of classes included morethan once in an inheri-tancelattice; the programmerhasthe choicewhether amultiply-includedbaseclasswill result in one or moresub-objectsbeing created.3. Detailsof constructionof objects, destructionof objects,and accesscontrol.Finally,some of the complexitiesand overheadsintroducedbythismultipleinheritancescheme are summarized.2. MultipleInheritanceConsider writing a simulationof a networkof computers.Eachnode in the networkis representedby an objectof class switch,eachuser or computerby an objectofclassTerminat, and each368 BjarneStroustrupcommunicationline by an objectof classtine. One way to moni-tor the simulation (or a real network of the samestructure)wouldbe to displaythe stateof objects of variousclasseson a screen.Eachobjectto be displayedis representedas an objectof classDispl.ayed.Objectsof classDispl.ayedare undercontrolof adisplaymanagerthatensures regular update of a screenand/ordata base. The classesTerminalandswitchare derived from aclass taskthat providesthe basicfacilitiesfor co-routine stylebehavior.Objects ofclass Taskare undercontrolofa taskmanager(scheduler)that managesthe real processor(s).Ideallytask and Displ.ayedare classes from a standardlibrary. If youwant to displaya terminalclass Terminal.mustbederivedfrom classDispl.ayed. Class Terminat,however,isalready derived from classTask. In a singleinheritancelanguage,such as the originalversionof C++ [Stroustrup 1986]or Simula67,wehaveonly two waysof solving this problem:derivingTaskfrom oisptayed or derivingDispl.ayedfrom task.Neitherisidealsince they bothcreatea dependencybetweenthe library ver-sionsof two fundamental and independentconcepts. Ideallyonewould wantto be ablechoosebetweensaying thata Terminal.is atask and a Displ.ayed;that Lineis a oispl.ayed but not a Task;and that a sh,itch is a Taskbut not a Displ.ayed.Theability to expressthis usinga classhierarchy,thatis, toderivea classfrom morethan one base class,is usuallyreferredtoas multipleinheritance. Otherexamplesinvolve the representa-tionof variouskinds of windowsin a windowsystem [Weinreb &Moon l98l I and the representationof variouskinds of processorsand compilersfor a multi-machine,multi-environmentdebugger[Cargill 1986].In general,multiple inheritanceallows a user to combineindependent(and not so independent)conceptsrepresentedasclassesinto a compositeconceptrepresentedas a derivedclass. Acommonway of using multipleinheritanceis for a designertoprovidesetsof baseclasseswith the intentionthat a usercreatesnew classesby choosingbase classesfrom eachoftherelevantsets. Thusa programmercreatesnew conceptsusing a recipe like"pick an A and/or a 8." In the window example,a usermightspecifya new kind of window by selectinga styleof windowinteraction(fromthe setof interaction base classes) and a styleofMultipleInheritance lor C++369appearance(fromthe setof baseclassesdefiningdisplayoptions).In the debuggerexample, a programmer would specifya debuggerby choosinga processor and a compiler.Given multiple inheritanceand H conceptseachof whichmightsomehowbe combinedwithoneof otherconcepts,weneed t'+mclassesto representall the combinedconcepts. Givenonlysingle inheritance,weneed to replicateinformationand pro-vide +l,l+H*tclasses. Singleinheritance handlescaseswhere N==1or M==1.The usefulness of multiple inheritancefor avoiding repli-cation hingeson the importanceof exampleswherethe valuesofI and t are both larger than t. It appears that exampleswithN>=2and il>=z are not uncommon;the window and debuggerexamplesdescribedabovewill typically haveboth n and l largerthan2.3. C* ImplementationStrategyBefore discussingmultiple inheritance and its implementationinC++ I will first describethe main points in the traditional imple-mentation of the Cr-+ singleinheritance classconcept.An objectof a Cr-+ classis representedby a contiguous regionof memory. A pointerto an objectof a class points to the firstbyteof that regionof memory.The compiler turns a callof amemberfunctionintoan "ordinaryo'functioncall with an "extrao'argument; that"extrao'argumentis a pointerto the object forwhich the member functionis called.Considera simpleclass R:rctassA {int a;void f( inti );l,l.In most ofthispaper data hiding issuesareignored to simplifythe discussionandshortenthe examples.This makessomeexamplesillegal. Changingthe wordct.assto structwouldmakethe exampleslegal,aswouldadding pubtic specifrersin theappropriateplaces.370 BjarneStroustrupAn objectof classA will look like thisI inta; INo information is placed in an n exceptthe integera specifred bythe user. No informationrelatingto (non-virtual) memberfunc-tions is placed in the object.A call of the memberfunctionR: : f :A* Pa;pa->f(2);is transformedby the compiler to an "ordinaryfunctioncall":f --F1A(pa,2) Objects of derived classesare composedby concatenatingthemembersof the classes involved:ctass A tinta; void f(int););ctass B :A tint b; void g(int); );ctass C:B {intc; void h(int); };Again,no "housekeeping"information is added, so an objectofclass c lookslike this:inta;intb;intc;Thecompiler n'knows" the position of all membersin an objectofa derivedclassexactlyas it doesfor an objectof a simpleclassand generates the same(optimal) codein both cases.Implementingvirtualfunctionsinvolvesa tableof functions.Consider:ctass A {int a;virtuaIvoid f( int);virtuaIvoidg(int);virtuaIvoidh(int);,iMultipleInheritance for C++ 37Iclass B :A {int b; void g(int); };classC :B {intc; void h(int);};In this case,a tableof virtualfunctions, the vtbt,contains theappropriatefunctions for a givenclassand a pointer to it is placedin every object.A classc objectlookslike this:int a; I vtbl.:vptr .int b; Iintc; IA::fB::gC::hA call to a virtualfunctionis transformedinto an indirectcallbythe compiler.For example,c* pc;Pc->g(2);becomes something like:(*(pc->vptr t I I ) ) (Pc,2) ;A multipleinheritancemechanismfor Cr+ mustpreservetheefficiencyandthe key featuresof this implementation scheme.4. Multiple Base ClassesGiven two classesctassA {...};ctassBt...);onecan designa third using bothas base classes:ctassC:4,8t...);This meansthat a c is an I and a B. Onemightequivalently2definec like this:classC:8,4t...];2. Exceptfor possiblesideeffectsin constructorsand destructors(accesstoglobalvari-ables,input operations,output operations,etc.).372 BjarneStroustrup4.1 ObjectLayoutAnobjectof classc can be laid out as a contiguousobjectlikethis:A partB partC partAccessinga memberof classesA, B or c is handledexactly asbefore: the compiler knows the location in the objectof eachmemberand generatesthe appropriatecode(without spuriousindirectionsor other overhead).4.2 MemberFunctionCallCalling a memberfunctionof R or c is identical to whatwas donein the singleinheritancecase.Calling a memberfunctionof agivena c* is slightly moreinvolved:c* p";pc->bf(2);//assumethat bf is a memberof BI Iandthat C hasno membernamedbfl/exceptthe oneinheritedfromBNaturally,B::bf () expects u s* (to becomeits ttris pointer). Toprovide it, a constantmust be addedto pc. Thisconstant,detta(B),is the relativeposition of the B part of c. This delta isknown to the compiler that transformsthe callinto:bf --F IB( (B*) ( ( char*)pc+deL ta(B)) ,2) Theoverhead is oneadditionof a constant per call of this kind.Duringthe executionof a member functionof a the function'sthispointerpoints to the a part of c:MultipleInheritance for Ct+ 373hlJe .A partB::bf's thisB partC partNotethat there is no space penalty involvedin using a secondbase class and thatthe minimal time penaltyis incurred only onceper call.4.3 AmbigaitiesConsider potentialambiguitiesif both n ands havea publicmemberi i:ctassA tintii;);ctassB {char* ii;};ctass C:A, B {};In this casec will havetwo members called i i, A:: i i and B:: i i.Thenc* pc;pc->ii;llerror: A::iior B::ii?is illegalsince it is ambiguous.Such ambiguitiescan be resolvedby explicit qualifrcation:pc-)A::ii;llCts A's iipc-)B::ii;llCts Brs iiA similar ambiguityarises if both R and s havea function f ( ):class A ( void f(););class B {intf();};ctassC:ArB{};c* pc;pc->f()llerror: A::f or B::f ?37 4BjarneStroustruppc->A::f(); llCts A's fpc->B::f(); llC.s B's fAs an alternative to specifyingwhich baseclassin eachcall of anf (), onemightdenean f o for c. c::f o mightcallthe baseclass functions.For example:class C:A, B tintf(){A::f();return B::f();});c* pc;pc->f()i llC:zf is cattedThis solution usuallyleads to cleanerprograms; it localizesthespecificationof the meaning of the namefor objects of a derivedclass to the declaration ofthederivedclass.4.4 CastingExplicit and implicitcastingmay also involvemodifyinga pointervalue with a delta:c* Pc;B* pb;pb = (B*)pc; llpb = (B*)((char*)pc+del.ta(B))pb = pc, l/pb = (B*)((char*)pc+detta(B))Pc = Pb; I Ierror: castneededpc = (C*)pb; llpc = (C*)((char*)pb-del.ta(B))Castingyieldsthe pointerreferringto the appropriatepart of thesameobject.pc ..A partPb ...B partC partMultipleInheritance r C+37 5Comparisons are interpreted in the sameway:pc == pb;llthat is,pc == (C*)pbllor equivalentty (B*)pc == pb//that is, (B*)((char*)pc+del.ta(B) == pbI /or equivalenttyll pc == (C*)((char*)pb-del.ta(B))Note that in both C and Cr+ castinghasalwaysbeen anoperatorthat producedonevalue givenanother ratherthan anoperatorthat simply reinterpreted a bit pattern.For example, onalmostall machines ( i nt ) .2 causescode to be executed;(f toat)(int).2 is notequal to .2. Introducingmultiple inheri-tance as describedherewill introduce caseswhere(char*)(B*)v !=(char*)vfor somepointer typeB*. Note, how-ever,that whens is a baseclassof c, {B*)v==(*)v==v.4.5 Zero Valued PointersPointerswith the value zero causea separateproblem in the con-text of multiplebaseclasses. Considerapplyingthe rulespresentedabove to a zero-valuedpointer:C*pc=0;B*pb=0;if (pb =-- 0)pb = pc;I/pb = (B*)((char*)pc+de[ta(B))if (pb == 0)The secondtestwouldfailsince pb would havethe value(B*) ( (char*)0+deI ta(B) ).Thesolutionis to elaborate the conversion (casting)operationto test for the pointer-value0: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)Theaddedcomplexity and run-timeoverheadare a test and anincrement.376 BjarneStroustrup5. Virtual FunctionsNaturally,memberfunctionsmay be virtual:ctassA {virtualvoid f();];ctass B {virtuaI void f();virtuaIvoid g(); ];ctassC :A,B {void f();};A* pa = ne C;B* pb = neC;C* pc = neC;pa->f ( ) ;pb->f ( ) ipc->f( ) iAll these callswill invokec: : f ( . Thisfollows directlyfromthedefinition of virtual. since class c is derived from class n andfrom classe.5.1 ImplementationOnentry to c: : f , the th i s pointermustpoint to the beginning ofthe c object(and not to the e part).However,it is not in generalknown at compiletimethat the s pointed to by pb is part of a cso the compilercannotsubtract the constantdel.ta(B). Conse-quently del.ta(B)mustbe stored so thatit can be found at runtime.Sinceit is only usedwhen callinga virtualfunctiontheobviousplaceto storeit is in the tableof virtualfunctions(vtbt).For reasons that will be explained below the deltais storedwitheachfunctionin the vtbl. so that a vtbl. entry will be of theform:3structvtb[-entry {void (*fct) ( );intdelta;);An objectof classc will look like this:3. TheAT&TCl+ 2.0implementationuses three freldsin this structure,butonlythetwo shown hereareused by the virtualfunctioncallmechanism;see Lippman&Stroustrup [ 1988].MultipteInheritance r C++377vPtr ...A partvtbl.:I C::f | 0 |vtbl.:I C::f | -del,ta(B) II B::s | 0 Ivptr ...B partC partpb->f()illcall of C::f://registervtb[-entry*vt = &pb-)vtbttindex(f)t;I Ivt.>fct) ((B*)((char*)pb+vt->detta))Note that the objectpointermayhaveto be adjusted to point tothe correctsub-objectbefore looking for the member pointingtothe vtbl.. Note also that each combination of base classandderivedclass hasits own vtbl.. For example,the vtbtfor s in cis differentfromthe vtbl. of a separatelyallocated a. Thisimpliesthat in generalan objectof a derivedclassneedsa vtbl,for eachbase class plusone for the derivedclass. However,aswithsingle inheritance,a derived classcan share a vtbt withitsfirst base so that in the example aboveonlytwo vtbl.sare usedforan object of type c (one for n in c combinedwithc'sownplusonefor e in c).Usingan int as the type of a storeddelta limitsthe size of asingleobject; that mightnotbe a badthing.5.2 AmbigaitiesThefollowing demonstrates a problem:ctassA {virtualvoid f()i]ictass B {virtualvoid f();];ctass C :A,B {void f()i}iC* pc = new C;pc->f ( ) i378 BjarneStroustruppc->A::f();pc->B::f();Explicit qualification"suppresses"virtuat so the lasttwocallsreally invoke the baseclassfunctions.Is thisa problem?Usually, no. Either c has an f < > and thereis no need to useexplicit qualificationor c hasno f f ( ) iA* pa = pc;pa->f ( ) i//ambiguous/linpLicitconversionof C* to A*l/not ambiguous:caIts A::f();The potentialambiguity in a callof t < I is detectedat the pointwherethe virtualfunctiontablesfor R and s in c are constructed.In otherwords,the declarationof C above is illegalbecauseitwould allow calls, such as pa->f< t, whichare unambiguous onlybecausetype information has been "lost"through an implicitcoercion;a call of t c I for an objectof type c is ambiguous.6. MultipleInclusionsA classcanhave any numberof base classes. For example,ctass A:81,82,83,84,85,B {...};It illegalto specify the sameclass twice in a list of base classes.For example,ctass A : B, B {...};//errorMultipleInheritance r C++ 379Thereason for thisrestrictionis thateveryaccessto a B memberwould be ambiguous and thereforeillegal; thisrestrictionalsosimplifres the compiler.6.1 Multiplesub-objectsA class may be included morethan once as a base class. Forexample:ctassLt...);ctassA :L t...);class B :L {...};ctass C :A , B {...};In such casesmultiple objects of the base class are partof anobjectof the derivedclass.For example,an objectof classc hastwo L's:one for and one for g:L part (of A)A partL part (of B)B partC partThis can even be useful.Think of I as a link class for a Simula-stylelinked list. In thiscase a c can be on both the list of Es andthe list of ss.380 BjarneStroustrup6.2 NamingAssumethatclassI in the exampleabove has a member m. Howcould a function c: : f refer to t: : m?The obviousansweris "byexplicit qualifrcation" :voidC::f(){A::m = B::m; }Thiswill worknicelyprovided neitherA nor e has a member m(exceptthe onetheyinheritedfrom L). Ifnecessary,thequalificationsyntax of C+r couldbe extended to allowthe moreexplicit:voidC::f(){A::L::m = B::L::m;}6.3 CastingConsiderthe exampleaboveagain.The factthat there are twocopiesof I makescasting(bothexplicit andimplicit)betweenl-*and c* ambiguous, and consequentlyillegal:C* pc = new C;L* p[ = pc;llerror: ambiguouspt = (L*)pc; I /error: sti l. Iambiguouspt = (L*)(A*)pc; llThe L in CrsApc = pt;l/error:ambiguouspc = (L*)pt illerror:stitIambiguouspc = (C*)(A*)pt illThe C containing A's LI don't expectthis to be a problem.Theplacewherethis willsurfaceis in caseswhere ns (or as) are handledby functionsexpecting an L; in thesecasesa c will notbe acceptabledespiteac beingan A:externf(L*);l/somestandard functionf(&aa);f(&cc);f((A*)&cc);I IfineI Ierror: ambiguousI IfineCasting is used for explicitdisambiguation.A aa;C cc;MultipleInheritance for Ct+ 3817. VirtualBase Classes\/hen a class c has twobaseclasses R and s thesetwo baseclassesgive riseto separatesub-objectsthat do not relate to eachotherin ways differentfrom any other and e objects. I callthisindependentmultipleinheritance. However,manyproposed usesof multipleinheritanceassume a dependence amongbaseclasses(for example,the style of providing a selectionof featuresfor awindowdescribedin $2). Such dependenciescan be expressed interms of an objectsharedbetweenthe variousderivedclasses. Inotherwords, there mustbe a way of specifying that a baseclassmustgive riseto only one objectin the final derivedclassevenifit is mentionedas a baseclass several times.To distinguish thisusage from independentmultiple inheritancesuch baseclasses arespecifiedto be virtual:ctassAtl :virtual h, t...];ctass Btl :virtuaIt., t...];ctass Ct, :Ahl , Bt, {...};A singleobjectof class w is to be shared betweennw andBu,;thatis, only one t, objectmustbe included in cw as the resultof deriv-ing cw fromRw and sr,,. Exceptfor giving riseto a unique objectin a derivedclass,a virtuat.baseclass behavesexactly like anon-virtualbase class.The"virtualness"of u is a property of the derivationspecifredby lw and sw and nota property of t.titself.Every virtuat basein an inheritanceDAGrefers to the sameobject.A class may be botha normaland a virtual base in an inheri-tanceDAG:cIassA:virtuatLt...ctassB:virtuatLt...ctassC:A,B{...};ctassD:L,C{...};A o object will havetwo sub-objectsof class L, onevirtualandone"normal."Virtualbase classesprovide a wayof sharinginformationwithinan inheritanceDAGwithout pushing the sharedinforma-tion to an ultimatebaseclass. virtualbasescan thereforebe usedto improve localityof reference. Another way of viewingclasses382 BjarneStroustrup););derived from a commonvirtual baseis as alternativeand compos-ableinterfaces to the virtual base.7.1 RepresentationThe objectrepresentinga virtualbaseclass u object cannot beplaced in a frxed positionrelative to both w and st, in all objects.Consequently,a pointerto ll mustbe stored in all objectsdirectlyaccessingthe u objectto allow accessindependentlyofits relativeposition.For example:Ab'l* paul = newAl;g* pbw = newBl'f;Cl'l* pcw = new ClllpaH . ->At', part IlvlBLJ part IlvlAll partBhrl partCll partLl partA class canhavean arbitrarynumberof virtual baseclasses.Onecan cast from a derivedclassto a virtual baseclass,butnotfrom a virtualbaseclass to a derivedclass. Theformerinvolvesfollowingthe virtual base pointer; the lattercannotbedonegiven the information availableat run time.Storinga"back-pointer"to the enclosingobject(s)is non-trivialin generaland was considered unsuitablefor Cr+ as was the alternative stra-tegyof dynamically keepingtrack of the objects "for which"agiven memberfunction invocationoperates.The uses of such aback-pointermechanismdid not seemto warrant the addedimplementationcomplexity,the extraspace requiredin objects,and the addedrun-timecost of initialization.Theinformation necessaryto cast froma virtual baseclass toa derivedclassis partof whatis neededto perform a virtualcallof a functiondeclared in the virtual baseand overridden by thederivedclass. The absenceof the back-pointercan thusbe com-pensatedfor by definingand callingappropriatevirtualfunctions:cIass B tvirtuaIvoid f();...];ctass D :virtual B {void f();...};voidg(B*p)',,insteadof casting,t to a D* here cal.l. f())Since explicitcasting is oftenbest avoided this techniqueactuallyleads to bettercodein manycases.384 BjarneStroustrupvlg();llAtl==g(,pcw->h();llC\l=zh()((Alt*)pcw)->f(); I /Bht::f ();A cwobjectmight look like this:. I Al'lpartvlCl'l partvtbt:. I BL, partvl...>lvptr . de Lta ( Bhl)-de t ta(l)-de Lta (l'l)-de t ta (t'l)0II hl partIl BU::fI AH::sI Ct'l:: h| l::kIn general,the delta storedwith a function pointerin a vtbl'isthe deltaof the classdefrningthe functionminusthe delta of theclassfor whichthe vtbl,is constructed.MultipleInheritance r C++ 385If w has a virtualfunction f that is re-defrnedin both nw andBt, but not in cu, an ambiguityresults. Such ambiguitiesare easilydetectedat the point wherecr.t's vtbt is constructed.Therule for detectingambiguitiesin a class lattice,or moreprecisely a directedacyclicgraph (DAG) of classes,is thatthere allre-defrnitionsof a virtualfunctionfrom a virtual baseclassmustoccur on a singlepath throughthe DAG. Theexampleabove canbe drawnas a DAGlike this:Br{tf}IINote that a call "up" through onepath of the DAG to a virtualfunctionmay resultin the callof a function(re-defrned) inanother path (as happened in the call tclin theexampleabove).7.3 Usingvirtual basesProgrammingwithvirtualbases is trickier than programming withnon-virtualbases.The problem is to avoid multiplecalls of afunctionin a virtualclasswhen that is not desired.Hereis a pos-siblestyle:ctass ' ,.-.protected:-f() tmystuff )publ.ic:f(){ -f(); });Each class provides a protectedfunctiondoing"its own stufl"-f ( ), for use by derived classesand a publicfunction f < I as theinterfacefor use by the "generalpublic."386 BjarneStroustrupIIAh,{s}IIIctass A :pubtic virtuat I'l {u ...protected:-f() {mYstuff }u...pubLic:f(){ -f(); }l::-f();}u ...);A derivedclassf ( I doesits "ownstuff' by calling -f ( ) and itsbaseclasses'"owr stuff'by callingtheir -f ( )s.cIass B :publ.icvirtuaI l'l{il...protected:-f() {mystuff }ll "'pubtic:f(){ -f(); w::-f();}t/...);In particular,thisstyleenables a classthatis (indirectly)derivedtwice from a classw to call td: : f ( ) onceonly:classC :publ.ic A, publicB, publicvirtuat ]l {u ...protected:-f() tmystuff )u ...pubti c:f()t -f(); A::-f();B::-f();U::-f();)u ,.-);Method combinationschemes,such as the onesfound in Lispsystems with multipleinheritance,rryereconsidered as a rvay ofreducingthe amountof codea programmerneededto writeincaseslike the oneabove.However,none of theseschemesappearedto be sufficientlysimple, general,and efficientenoughtowarrant the complexity it would add to Cr+.MultipleInheritance r C++ 3878. Constructorsand DestructorsConstructorsfor baseclasses are called before the constructorfortheir derivedclass. Destructorsfor baseclassesare calledafterthe destructorfor their derivedclass. Destructorsare called in thereverse orderof their declaration.Argumentsto baseclassconstructorscan be specifred like this:ctassA{A(int);}ictassBtB(int);)ictass C:A,virtual B {C(int a, int b) :A(a),B(b) t...));Constructorsare executedin the orderthey appearin the listof bases exceptthata virtual baseis alwaysconstructed beforeclassesderivedfrom it.A virtualbaseis alwaysconstructed(once only) by its "mostderived"class. For example:ctass V {V(); V(int);...};ctass A:virtual V {A(); A(int);...}icIass B:virtuaIV {B(); B(int),...t,ctass C :A, B {C(); C(int), ...t,v v(1);lluse v(int)A a(2);//use v(int)B b(3) l/use V()c c(4) il/use v()9. AccessControlTheexamplesaboveignoreaccesscontrol considerations.A baseclassmay be pubticor private. In addition,it may be virtuat.For example:classD:81 llprivate (by defautt),/ Inon-virtua[(by defaul.t), virtuaI82//private (by defaul.t),virtuaI, pubtic 83llpublic, non-virtual//(by defauLt)388 BjarneStroustrup, pubtic virtual.84 {il...);Note that a accessor virtual. specifrerapplies to a singlebaseclassonly.For example,ctassC : publ.ic A, B t...);declaresa publicbase R and a private bases.A virtualclassthat is accessiblethrough a path is accessibleevenif other paths to it use private derivation.10. OverheadsTheoverhead in usingthis schemeis:l. One subtractionof a constantfor each useof a member in abaseclassthat is includedas the secondor subsequent base.2. One word per functionin eachvtbt (to hold the delta).3. One memoryreferenceand onesubtraction for eachcallofa virtualfunction.4. One memoryreferenceand onesubtraction for accessof abaseclassmember of a virtual baseclass.Note that overheads l. and 4. are only incurred wheremultipleinheritance is actuallyused,butoverheads2. and3. are incurredfor each classwithvirtual functions and for each virtual functioncallevenwhen multipleinheritanceis notused. Overheadsl. and4. are only incurred when membersof a second or subsequentbaseare accessed "fromthe outside";a memberfunctionof a vir-tual baseclassdoesnot incurspecialoverheadswhen accessingmembers of its class.Thisimplies that except for 2. and 3. youpay only for whatyou actuallyuse;2. and 3. impose a minor overhead on the virtualfunctionmechanismeven whereonly singleinheritanceis used.This latteroverheadcould be avoidedby using an alternativeimplementationof multipleinheritance,but I don't knowof suchan implementationthat is also fasterin the multiple inheritancecaseand as portableas the schemedescribedhere.MultipleInheritance r C++ 389Fortunately,these overheadsare notsignificant.Thetime,space,and complexityoverheadsimposedon the compiler toimplementmultiple inheritance are not noticeable to the user.11. But is it Simple to Use?Whatmakes a languagefacilityhardto use?l. Lots of rules.2. Subtledifferencesbetweenrules.3. Inabilityto automaticallydetectcommonerrors.4. Lackof generality.5. Defrciencies.The first twocaseslead to difficulty of learningand remembering,causing bugs due to misuseand misunderstanding.Thelasttwocasescause bugs and confusionas the programmertriesto circum-ventthe rulesand "simulateo'missingfeatures.Case3. causesfrustrationas the programmerdiscoversmistakesthe hardway.Themultipleinheritance scheme presentedhere providestwoways of extending a class's name space:l. A base class.2. A virtual baseclass.These are two waysof creating/specifyinga newclassratherthanways of creating two different kinds of classes.The rules for usingthe resultingclassesdo not dependon how the namespace wasextended:l. Ambiguitiesare illegal.2. Rules for useof members are what they werefor singleinheritance.3. Visibility rules are what they werefor singleinheritance.4. lnitializationrules are whatthey werefor singleinheritance.Violationsof theserules are detectedby the compiler.390 Bjarne StroustrupIn otherwords,the multipleinheritancescheme is only morecomplicatedto usethan the existingsingleinheritance schemeinthatl. You can extenda class'sname space morethan once(withmorethan onebaseclass).2. You canextenda class'sname space in twowaysratherthan in onlyoneway.In addition, caremustbe taken to take the sharing intoaccount when programmingmember functions of classes with vir-tual base classes;seesection 7 above.This appearsminimaland constitutesan attempt to provide aformaland (comparatively) safesetof mechanismsfor observedpracticesand needs.I think that the schemedescribedhereis "assimpleas possible,but no simpler."A potentialsourceof problems existsin the absenceof o'sys-temprovided back-pointers"from a virtual baseclassto itsenclosingobject.In some contexts,it might also be a problemthatpointerstosub-objectsare usedextensively.This will affect programs thatuse explicitcasting to non-object-pointertypes(suchas char*)and "extralinguistic"tools(suchas debuggersand garbagecollec-tors). Otherwise,and hopefullynormally,all manipulationofobject pointersfollows the consistentrulesexplainedin $4, $7,and $8 and is invisibleto the user.12. ConclusionsMultipleinheritance is reasonablysimple to add to Cr+ in a waythat makesit easy to use. Multiple inheritanceis nottoo hard toimplement, sinceit requires only very minor syntacticextensions,and frts naturallyinto the (static) type structure. The implemen-tationis veryefficientin both timeand space.Compatibility withC is notaffected.Portabilityis not afected.MultipteInheritance r C++ 391AcknowledgementsIn 1984I had a long discussion with Stein KrogdahlfromtheUniversity of Oslo, Norway. He haddeviseda schemefor imple-menting multipleinheritancein Simulausing pointermanipula-tionbasedon additionand subtaction of constants. Krogdahl[1984] describes this work. Tom Cargill, JimCoplien,Brian Ker-nighan,AndyKoenig,I-arry Mayka, DougMcllroy,and JonathanShopirosuppliedmanyvaluablesuggestionsand questions.392 BjarneStroustrupAppendixTheoriginalmultiple inheritance des as presented to the EUUGconferencein Helsinki in May 1987 containeda notion of delega-tion.a Briefly, a userwas allowedto specifya pointer to someclassamongthe baseclasses in a classdeclarationand the objectthus designatedwouldbe usedexactly as if it was an objectrepresentinga baseclass.For example:ctass B {intb; void f();};ctass C : *p tB* p;intc; );The : *p meant thatmembers of the object pointed to by p couldbe accessedexactly as if they weremembersof classc:void f(C*q){q->f()i)l/that is,q-)p-)f()An object of classc looked somethinglike this after c: : p hasbeen initialized:B*intp;ciII intb; IThis conceptlookedvery promising for representing structuresthat requiremoreflexibilitythanis provided by ordinaryinheri-tance. In particular, assignmentto a delegationpointer could beused to reconfigurean objectat run-time. The implementationwas trivial andthe run-timeand space efficiencyideal.Unfor-tunately,everyuserof this mechanism sufferedseriousbugs andconfusion. Becauseof thisthe delegationmechanismwas notincludedin Cr+.I suspectthe fundamentalproblem with this variantof thenotionof delegation was thatfunctionsof the delegatingclasscouldnot overridefunctions of the class derivedto. Allowingsuch overriding would be at oddswith the Cr+ strategyof static4. Gul Agha,An Overviewof Actor languages,SIGPLANNotices, pp. 58-7,OctoberI 986.MultipleInheritance for C++ 393type checking and ambiguity resolution (consider the caseof anobjectof a classwithvirtual functions delegatedto by severalobjects of different classes).394 BjarneStroustrupReferencesTomCargill, PI:A CaseStudyin Object-OrientedProgramming,OOPSIA'86 Proceedings,pages350-360,September1986.Stein Krogdahl,An Efficient Implementationof SimulaClasseswithMultiplePrefrxing,ResearchReport No.83June1984,Universityof Oslo, Instituteof Informatics.Stan Lippmanand BjarneStroustrup,Pointersto Members in Ct+,Proc.USENIXCt+ Conference,Denver,October1988.BjarneStroustrup,TheC++ ProgrammingLanguage,Addison-Wesley,1986.BjarneStroustrup,What is "Object-OrientedProgramming!",Proc.ECOOP, Springer VerlagLectureNotes in ComputerScience, Vol.276,Jane 1987.BjarneStroustrup,TheEvolutionof C++:1985-1989,ComputingSystemsVol. 2 No.3,Fall1989.Daniel Weinreband David Moon, Lisp MachineManual,Symbolics,Inc.1981.lsubmitted May 4, 1989; revisedAug.28,1989; acceptedSept. 2, 19891Multipte Inheritance for C++ 395