3-1) C++ Multiple Inheritance
revised Nov 15, 2004


C++ Provides Multiple inheritance

Public and Private and Protected Inheritance can be combined

Memory can become very tricky

Syntax:

class A{ int a; ...};

class B{int b; ...};

class C : public A, pulic B {int c; ...};
// C has public base classes  A and B

a C object will have memmory:  A::a, B::b, C::c

class D: pulic A, private B {int d; ...};
//D has public base class A and private base class B

a D object will have memory A::a, B::b, D::d;




Public  Inheritance:

Public inheritance is appropriate for "is a" relationships

class BankAccount{public: deposit(float amount); ...}
class SavingAccount : public BankAccount {  ...};
 

SavingAccount s;
s.deposit(100); //inherits bank account behaviour
 
 

A SavingAccount is a BankAcount


Multiple inheritance allows objects to represent several (disjoint) types.

class Phone{public: dial(); ...};
class Graphic{ public: draw(); ...};

class PhoneWindow : public Phone, public Graphic {....}

updateWindow(Graphic * gp) {gp->draw(); }
makeCall(Phone * pp) {pp->dial(); }

PhoneWindow * p = new PhoneWindow;

makeCall(p); //p being used as Phone pointer
updateWindow(p); //p being used as Graphic pointer

A PhoneWindow is a Phone and it is a Graphic

But, memory becomes tricky in these situations:

#include <iostream.h>

class A{
    int a1,a2;
};
class B{
    int b1,b2, b3;
};

class C : public A, public B{
    int c1,c2;
};

void fooA(A & anA) {
    cout << "fooA: " << &anA << "\n";
}
void fooB(B & aB) {
    cout << "fooB: " << &aB << "\n";
}

void main(void) {
   C ac;
   cout << "main: " << &ac << "\n";
   fooA(ac);
   fooB(ac);
}

/*OUTPUT
main: 0x0012FF64
fooA: 0x0012FF64
fooB: 0x0012FF6C  ----why different
*/


Public  and Private Inheritance (MIXIN):

Public inheritance is appropriate for "is a" relationships
Private inheritance is approriate for a "part of" relationship

class Vector{public: operator[](int i); ...}
class Stack {public: void push(T & item); T & pop();  ...};

class MyStack : public Stack, private Vector { ...};

MyStack s;
s.push(x); s.pop(); //OK
s[3] = x; //ERROR the [] operator is private
 
 
 

A MyStack is a Stack, but a Vector is part of MyStack
(Clients of MyStack are not aware that it has Vector properties

Protected inheretance allows further subclassing; private inheritance does not
 
 


Common Base Classes:

Example1:

class A{int a; ...}
class B1 : public A { int b1; ...};
class B2 : public A { int b2; ...};

class C : public B1, public B2 {int c; ...};

a C object will have memory
A::a,
B1::b1,
A::a,
B2::b2,
C::c

(Notice common base class memory is repeated)
 

Example2 (Virtual Inheritance)

class A{int a; ...}
class B : virtual public A { int b1; ...};
class B2 : virtual public A { int b2; ...};

class C : public B1, public B2 {int c; ...};

a C object will have memory
A::a,
B1::b1,
B2::b2,
C::c

(Notice common base class memory is NOT repeated)


Multiple Inheritance Examples
Study these examples and make sure you understand why the output is as it is.


 

#include <iostream>

using namespace std;

 

//Multiple inheritance with common base class

//example 1

 

class A {

public:

   A() {cout << "A()\n";}

   A(int i) {cout << "A(int)\n";}

};

 

class B1 : public A {

public:

   B1(): A(5) {cout << "B1()\n";}

};

 

class B2: public A {

public:

   B2() {cout << "B2()\n";}

};

 

class C: public B1, public B2 {

public:

   C() {cout << "C()\n";}

};

void main() {

C c;

}

 

 

/*OUTPUT

A(int)

B1()

A()

B2()

C()

END OUTPUT */




//example 2
//separate memory for common base class

#include <iostream.h>

class A {
public:
 A() :mA(0) {cout << "A()\n";}
 A(int i): mA(i) {cout << "A(int)\n";}
 ~A() {cout << "~A()\n";}
 void print() {cout << "mA= " << mA <<"\n";}

private:
 int mA;
};

class B1 : public A {
public:
 B1(): mB1(0) {cout << "B1()\n";}
 ~B1() {cout << "~B1()\n";}

 void print() {A::print();
   cout << "mB1= " << mB1 <<"\n";}

private:
 int mB1;
};

class B2: public A {
public:
 B2() : mB2(0){cout << "B2()\n";}
 B2(int i) : mB2(i), A(i) {cout << "B2()\n";}
 ~B2() {cout << "~B2()\n";}

 void print() {A::print();
   cout << "mB2= " << mB2 <<"\n";}
private:
 int mB2;
};

class C: public B1, public B2 {
public:
 C(): mC(0) {cout << "C()\n";}
 C(int i): mC(i), B2(i) {cout << "C()\n";}
 ~C() {cout << "~C()\n";}

 void print() {B1::print(); B2::print();
    cout << "mC= " << mC << "\n"; }
private:
  int mC;
};

void main() {
  C c(5);
  c.print();
}

/*OUTPUT
A()
B1()
A(int)
B2()
C()
mA= 0
mB1= 0
mA= 5
mB2= 5
mC= 5
~C()
~B2()
~A()
~B1()
~A()
END OUTPUT */



#include <iostream.h>
//the need for virtual destructors and print functions

class A {
public:
 A() :mA(0) {cout << "A()\n";}
 A(int i): mA(i) {cout << "A(int)\n";}
 virtual ~A() {cout << "~A()\n";}
 virtual void print() {cout << "mA= " << mA <<"\n";}

private:
 int mA;
};

class B1 :   public A {
public:
 B1(): mB1(0) {cout << "B1()\n";}
    B1(int i): A(i), mB1(i) {cout << "B1()\n";}

 ~B1() {cout << "~B1()\n";}

 void print() {A::print();
   cout << "mB1= " << mB1 <<"\n";}

private:
 int mB1;
};

class B2:   public A {
public:
 B2() : mB2(0){cout << "B2()\n";}
 B2(int i) : mB2(i), A(i) {cout << "B2()\n";}
 ~B2() {cout << "~B2()\n";}

 void print() {A::print();
   cout << "mB2= " << mB2 <<"\n";}
private:
 int mB2;
};

class C: public B1, public B2 {
public:
 C(): mC(0) {cout << "C()\n";}
 C(int i): mC(i), B1(i*10), B2(i) {cout << "C()\n";}
 ~C() {cout << "~C()\n";}

 void print() {B1::print(); B2::print();
    cout << "mC= " << mC << "\n"; }
private:
  int mC;
};

void main() {
  C *p = new C(5); //A *p would be ambiquous
                   //B1 *p or B2 *p OK but need virtual destructors
                   //and methods (like print)
  p->print();
  delete p;
}

/*OUTPUT
A(int)
B1()
A(int)
B2()
C()
mA= 50
mB1= 50
mA= 5
mB2= 5
mC= 5
~C()
~B2()
~A()
~B1()
~A()
END OUTPUT */



#include <iostream.h>
//Supressing duplicate memory with virtual inheritance

class A {
public:
 A() :mA(0) {cout << "A()\n";}
 A(int i): mA(i) {cout << "A(int)\n";}
 virtual ~A() {cout << "~A()\n";}
 virtual void print() {cout << "mA= " << mA <<"\n";}

private:
 int mA;
};

class B1 :   virtual public A {
public:
 B1(): mB1(0) {cout << "B1()\n";}
    B1(int i): A(i), mB1(i) {cout << "B1()\n";}

 ~B1() {cout << "~B1()\n";}

 void print() {A::print();
   cout << "mB1= " << mB1 <<"\n";}

private:
 int mB1;
};

class B2:   virtual public A {
public:
 B2() : mB2(0){cout << "B2()\n";}
 B2(int i) : mB2(i), A(i) {cout << "B2()\n";}
 ~B2() {cout << "~B2()\n";}

 void print() {A::print();
   cout << "mB2= " << mB2 <<"\n";}
private:
 int mB2;
};

class C: public B1, public B2 {
public:
 C(): mC(0) {cout << "C()\n";}
 C(int i): mC(i), B1(i*10), B2(i) {cout << "C()\n";}
 ~C() {cout << "~C()\n";}

 void print() {B1::print(); B2::print();
    cout << "mC= " << mC << "\n"; }
private:
  int mC;
};

void main() {
  A *p = new C(5); //notice A *p not ambiquous
  p->print();
  delete p;
}

/*OUTPUT
A()    //notice A(int) not called
B1()
B2()
C()
mA= 0
mB1= 50
mA= 0
mB2= 5
mC= 5
~C()
~B2()
~B1()
~A()
END OUTPUT */



#include <iostream.h>

class A {
public:
 A() :mA(0) {cout << "A()\n";}
 A(int i): mA(i) {cout << "A(int)\n";}
 virtual ~A() {cout << "~A()\n";}
 virtual void print() {cout << "mA= " << mA <<"\n";}

private:
 int mA;
};

class B1 :   virtual public A {
public:
 B1(): mB1(0) {cout << "B1()\n";}
    B1(int i): A(i), mB1(i) {cout << "B1()\n";}

 ~B1() {cout << "~B1()\n";}

 void print() {A::print();
   cout << "mB1= " << mB1 <<"\n";}

private:
 int mB1;
};

class B2:   virtual public A {
public:
 B2() : mB2(0){cout << "B2()\n";}
 B2(int i) : mB2(i), A(i) {cout << "B2()\n";}
 ~B2() {cout << "~B2()\n";}

 void print() {A::print();
   cout << "mB2= " << mB2 <<"\n";}
private:
 int mB2;
};

class C: public B1, public B2 {
public:
 C(): mC(0) {cout << "C()\n";}
 C(int i): mC(i), B1(i*10), B2(i), A(i) {cout << "C()\n";}
             //A(i) not allowed without virtual inheritance
 ~C() {cout << "~C()\n";}

 void print() {B1::print(); B2::print();
    cout << "mC= " << mC << "\n"; }
private:
  int mC;
};

void main() {
  A *p = new C(5);
  p->print();
  delete p;
}

/*OUTPUT
A(int) //explicitly called in C(int)
B1()
B2()
C()
mA= 5
mB1= 50
mA= 5
mB2= 5
mC= 5
~C()
~B2()
~B1()
~A()
END OUTPUT */



/*
Refering to object parts through different base pointers.
Notice the correct version of A's memory is updated and that the object
can be destroyed through any base pointer.
*/
#include <iostream.h>

class A {
public:
 A() :mA(0) {cout << "A()\n";}
 A(int i): mA(i) {cout << "A(int)\n";}
 virtual ~A() {cout << "~A()\n";}
 virtual void print() {cout << "mA= " << mA <<"\n";}

public:
 int mA;
};

class B1 :    public A {
public:
 B1(): mB1(0) {cout << "B1()\n";}
    B1(int i): A(i), mB1(i) {cout << "B1()\n";}

 ~B1() {cout << "~B1()\n";}

 void print() {A::print();
   cout << "mB1= " << mB1 <<"\n";}

private:
 int mB1;
};

class B2:    public A {
public:
 B2() : mB2(0){cout << "B2()\n";}
 B2(int i) : mB2(i), A(i) {cout << "B2()\n";}
 ~B2() {cout << "~B2()\n";}

 void print() {A::print();
   cout << "mB2= " << mB2 <<"\n";}
private:
 int mB2;
};

class C: public B1, public B2 {
public:
 C(): mC(0) {cout << "C()\n";}
 C(int i): mC(i), B1(i*10), B2(i) {cout << "C()\n";}
 ~C() {cout << "~C()\n";}

 void print() {B1::print(); B2::print();
    cout << "mC= " << mC << "\n"; }
private:
  int mC;
};

void main() {
  C *cp = new C(5);
  B1 *b1p = cp;
  B2 *b2p = cp;
  b1p->mA = 100;
  b2p->mA = 200;
  b1p->print();
  delete b2p;
}

/*OUTPUT
A(int)
B1()
A(int)
B2()
C()
mA= 100
mB1= 50
mA= 200
mB2= 5
mC= 5
~C()
~B2()
~A()
~B1()
~A()
END OUTPUT */