In C++, a class can inherit from more than one
class.
This is called multiple inheritance.
Some other OOPS languages like Java, do not support multiple inheritance.
Here MI class declaration
uses B followed by A in base class specification. So B ctor is called
before A ctor when MI object is created even though in member
initialization list, A class ctor is called first.
Dreaded Diamond problem
Some other OOPS languages like Java, do not support multiple inheritance.
Syntax for
multiple
inheritance is
class cls-name:public base-cls1,public base-cls2,public base-cls3 { /*code*/ }
We are specifying multiple classes as base classes here. The base
class list is comma
separated and has access specifier for each base class. Each of these
base classes must have been declared earlier.
Derived
class objects
contain sub-objects of each of these base classes.
class LandAnimal {
int legs; public: void walk() { cout<<"walks"; } }; class WaterAnimal {
int fins; public: void swim() { cout<<"swims"; } }; class Amphibian:public LandAnimal,public WaterAnimal { }; int main() { Amphibian frog; frog.walk(); frog.swim(); }
Output
walks
swims
In the
above example, class
Amphibian inherits
from 2 classes - LandAnimal
and WaterAnimal.
The derived class has members
of both these base classes. It can call both walk() and swim()
functions. We construct an object of this class and it has both data members legs and fins and it has functions swim and walk.
Size of a Ambphibian object = size of LandAnimal+size of WaterAnimal.
Constructors
The derived class constructors
and
destructors in multiple inheritance will call all of the base
class constructors and destructors.
The order of constructor calls is same as declaration order of
base classes.
Amphibian
constructor in the earlier example, will call LandAnimal constructor
first, then WaterAnimal constructor and finally Amphibian constructor. And
order of destructor calls is reverse of order of constructor
calls.
class A { int n1; int n2; public: A(int a,int b):n1(a),n2(b) {cout<<"A ctor ";} }; class B { int n3; int n4; public: B(int a,int b):n3(a),n4(b) {cout<<"B ctor ";} }; class MI:public B, public A { int m; public: MI(int num=0):m(num),A(num,num),B(num,num) {cout<<"Derived ctor";} }; int main(int argc, char **argv) { MI obj1(10); }
output of program
B ctor A ctor Derived ctor
When there
are multilevel and multiple inheritances
together, derived
class may contain more than one instance of an ancestor class. In such
a situation, using
a member from this ancestor class throws an ambiguity error.
class A { int m; public: void setm(int a){m = a;}; int getm(){return m;} void print(){cout<<"m"<<m<<endl;} }; class B: public A { public: B(){setm(10);}; }; class C:public A { public: C() {setm(20);}; }; class D:public B,public C { /*multiple inherited class*/ }; int main() { D obj; cout<<obj.getm();/*error*/ obj.print();/*error*/ }
When we
compile this program obj.print()
and obj.getm() throw
ambiguity error.
obj has
members of A class duplicated one via B class and another via C class.
When
calling print() or getm() , compiler is unable to decide whether to
call these functions of B class or of C class.
This is
called dreaded diamond problem because shape of inheritance
diagram in this case looks like a diamond.
To avoid
this error, virtual
inheritance is used.
Virtual
Inheritance
In virtual
inheritance, when there are multiple paths
to a base class, this base class object is included only once.
Virtual inheritance is implemented using virtual keyword before base class name in derived class definition.
Virtual inheritance is implemented using virtual keyword before base class name in derived class definition.
class A { int m; public: int getm(){return m;} void setm(int a){m = a;} void print(){cout<<"A print";} }; class B:virtual public A { /***code**/ }; class C:public virtual A { /***code**/ }; class D:public B,public C { /**this has only one sub object of A*/ }; int main() { D obj; obj.print();/*No error*/ }
Both B and
C classes use virtual inheritance. By using virtual keyword, we are ensuring that only one copy of a A class's member variables are inherited by grandchild derived classes.
So D which inherits from both B and C, it is inheriting only one sub-object of A class. So there is only one data member called m in D class and only one print() function. There will not be any ambiguity when any member of A is being used from D class object because D object will have only one sub-object of A class.
So D which inherits from both B and C, it is inheriting only one sub-object of A class. So there is only one data member called m in D class and only one print() function. There will not be any ambiguity when any member of A is being used from D class object because D object will have only one sub-object of A class.
Also you can observe that obj
causes A class constructor to be called
only once and A destructor to be called only once.
Comments
Post a Comment