Multiple Inheritance is a feature of C++ where a class can inherit from more than one classes.

  The constructors of inherited classes are called in the same order in which they are inherited. For example, in the following program, B’s constructor is called before A’s constructor.

 1 #include<iostream>
2 using namespace std;
3
4 class A
5 {
6 public:
7 A()
8 {
9 cout << "A's constructor called" << endl;
10 }
11 };
12
13 class B
14 {
15 public:
16 B()
17 {
18 cout << "B's constructor called" << endl;
19 }
20 };
21
22 class C: public B, public A // Note the order
23 {
24 public:
25 C()
26 {
27 cout << "C's constructor called" << endl;
28 }
29 };
30
31 int main()
32 {
33 C c;
34 return 0;
35 }

  Output:

  B's constructor called
  A's constructor called
  C's constructor called
  

  The destructors are called in reverse order of constructors.

  The diamond problem
  The diamond problem occurs when two superclasses of a class have a common base class.

  For example, in the following diagram, the TA class gets two copies of all attributes of Person class, this causes ambiguities.

  For example, consider the following program.

 1 #include<iostream>
2 using namespace std;
3 class Person
4 {
5 // Data members of person
6 public:
7 Person(int x)
8 {
9 cout << "Person::Person(int ) called" << endl;
10 }
11 };
12
13 class Faculty : public Person
14 {
15 // data members of Faculty
16 public:
17 Faculty(int x):Person(x)
18 {
19 cout<<"Faculty::Faculty(int ) called"<< endl;
20 }
21 };
22
23 class Student : public Person
24 {
25 // data members of Student
26 public:
27 Student(int x):Person(x)
28 {
29 cout<<"Student::Student(int ) called"<< endl;
30 }
31 };
32
33 class TA : public Faculty, public Student
34 {
35 public:
36 TA(int x):Student(x), Faculty(x)
37 {
38 cout<<"TA::TA(int ) called"<< endl;
39 }
40 };
41
42 int main()
43 {
44 TA ta1(30);
45 }

  Output:

  Person::Person(int ) called
  Faculty::Faculty(int ) called
  Person::Person(int ) called
  Student::Student(int ) called
  TA::TA(int ) called
  

  In the above program, constructor of ‘Person’ is called two times. Destructor of ‘Person’ will also be called two times when object ‘ta1′ is destructed. So object 'ta1' has two copies of all members of ‘Person’, this causes ambiguities(歧义). The solution to this problem is ‘virtual’ keyword. We make the classes ‘Faculty’ and ‘Student’ as virtual base classes to avoid two copies of ‘Person’ in ‘TA’ class.

  For example, consider the following program.

 1 #include<iostream>
2 using namespace std;
3 class Person {
4 public:
5 Person(int x)
6 {
7 cout << "Person::Person(int ) called" << endl;
8 }
9 Person()
10 {
11 cout << "Person::Person() called" << endl;
12 }
13 };
14
15 class Faculty : virtual public Person
16 {
17 public:
18 Faculty(int x):Person(x)
19 {
20 cout<<"Faculty::Faculty(int ) called"<< endl;
21 }
22 };
23
24 class Student : virtual public Person
25 {
26 public:
27 Student(int x):Person(x)
28 {
29 cout<<"Student::Student(int ) called"<< endl;
30 }
31 };
32
33 class TA : public Faculty, public Student
34 {
35 public:
36 TA(int x):Student(x), Faculty(x)
37 {
38 cout<<"TA::TA(int ) called"<< endl;
39 }
40 };
41
42 int main()
43 {
44 TA ta1(30);
45 }

  Output:

  Person::Person() called
  Faculty::Faculty(int ) called
  Student::Student(int ) called
  TA::TA(int ) called
  

  In the above program, constructor of ‘Person’ is called once. One important thing to note in the above output is, the default constructor of ‘Person’ is called. When we use ‘virtual’ keyword, the default constructor of grandparent class is called by default even if the parent classes explicitly call parameterized constructor.

  How to call the parameterized constructor of the ‘Person’ class? The constructor has to be called in ‘TA’ class.

  For example, see the following program.

 1 #include<iostream>
2 using namespace std;
3 class Person {
4 public:
5 Person(int x)
6 {
7 cout << "Person::Person(int ) called" << endl;
8 }
9 Person()
10 {
11 cout << "Person::Person() called" << endl;
12 }
13 };
14
15 class Faculty : virtual public Person
16 {
17 public:
18 Faculty(int x):Person(x)
19 {
20 cout<<"Faculty::Faculty(int ) called"<< endl;
21 }
22 };
23
24 class Student : virtual public Person
25 {
26 public:
27 Student(int x):Person(x)
28 {
29 cout<<"Student::Student(int ) called"<< endl;
30 }
31 };
32
33 class TA : public Faculty, public Student
34 {
35 public:
36 TA(int x):Student(x), Faculty(x), Person(x) //the difference
37 {
38 cout<<"TA::TA(int ) called"<< endl;
39 }
40 };
41
42 int main()
43 {
44 TA ta1(30);
45 }

  Output:

  Person::Person(int ) called
  Faculty::Faculty(int ) called
  Student::Student(int ) called
  TA::TA(int ) called

  In general, it is not allowed to call the grandparent’s constructor directly, it has to be called through parent class. It is allowed only when ‘virtual’ keyword is used.

  

  As an exercise, predict the output of following programs.

  Question 1

 1 #include<iostream>
2 using namespace std;
3
4 class A
5 {
6 int x;
7 public:
8 void setX(int i)
9 {
10 x = i;
11 }
12 void print()
13 {
14 cout << x;
15 }
16 };
17
18 class B: public A
19 {
20 public:
21 B()
22 {
23 setX(10);
24 }
25 };
26
27 class C: public A
28 {
29 public:
30 C()
31 {
32 setX(20);
33 }
34 };
35
36 class D: public B, public C
37 {43 };
44
45 int main()
46 {
47 D d;
48 d.print();
49 return 0;
50 }

  编译错误: 'D::print' is ambiguous

  Question 2

 1 #include<iostream>
2 using namespace std;
3
4 class A
5 {
6 int x;
7 public:
8 void setX(int i)
9 {
10 x = i;
11 }
12 void print()
13 {
14 cout << x;
15 }
16 };
17
18 class B: virtual public A
19 {
20 public:
21 B()
22 {
23 setX(10);
24 }
25 };
26
27 class C: virtual public A
28 {
29 public:
30 C()
31 {
32 setX(20);
33 }
34 };
35
36 class D: public B, public C
37 {
38
39 };
40
41 int main()
42 {
43 D d;
44 d.print();
45 return 0;
46 }

  Output:  20

  Please write comments if you find anything incorrect, or you want to share more information about the topic discussed above.
  

  转载请注明:http://www.cnblogs.com/iloveyouforever/

  2013-11-26  20:11:35

Multiple Inheritance in C++的更多相关文章

  1. Multiple inheritance in Go

    原文:http://golangtutorials.blogspot.com/2011/06/multiple-inheritance-in-go.html --------------------- ...

  2. 面向对象程序设计-C++ Inheritance & Multiple inheritance & RTTI【第十三次上课笔记】

    Sadly, 这节课带过去的笔记本没电了 T^T 导致没有一行 Code, Sorry 笔记如下: Shape * p1; //使用指针创建对象的方法 p = new Circle (2.0); Sh ...

  3. 条款40:明智而审慎地使用多重继承(use multiple inheritance judiciously)

    NOTE: 1.多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. 2.virtual 继承会增加大小 速度 初始化(及赋值)复杂度等等成本.如果virtual base ...

  4. Memory Layout for Multiple and Virtual Inheritance

    Memory Layout for Multiple and Virtual Inheritance(By Edsko de Vries, January 2006)Warning. This art ...

  5. JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance

    // the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...

  6. [置顶] c++类的继承(inheritance)

    在C++中,所谓"继承"就是在一个已存在的类的基础上建立一个新的类.已存在的类(例如"马")称为"基类(base class )"或&quo ...

  7. Classical Inheritance in JavaScript

    JavaScript is a class-free, object-oriented language, and as such, it uses prototypal inheritance in ...

  8. (转) Friendship and inheritance

    原地址: http://www.cplusplus.com/doc/tutorial/inheritance/ Friend functions In principle, private and p ...

  9. <Effective C++>读书摘要--Inheritance and Object-Oriented Design<二>

    <Item 36> Never redefine an inherited non-virtual function 1.如下代码通过不同指针调用同一个对象的同一个函数会产生不同的行为Th ...

随机推荐

  1. 攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup

    攻防世界 WEB 高手进阶区 TokyoWesterns CTF shrine Writeup 题目介绍 题目考点 模板注入 Writeup 进入题目 import flask import os a ...

  2. Vue 之 Mixins (混入)的使用

    是什么 混入 (mixins): 是一种分发 Vue 组件中可复用功能的非常灵活的方式.混入对象可以包含任意组件选项.当组件使用混入对象时,所有混入对象的选项将被合并到组件本身,也就是说父组件调用混入 ...

  3. JMeter接口自动化发包与示例

    JMeter接口自动化发包与示例 近期需要完成对于接口的测试,于是了解并简单做了个测试示例,看了看这款江湖上声名远播的强大的软件-Jmeter靠不靠谱. 官网:https://jmeter.apach ...

  4. EDG夺冠!用Python分析22.3万条数据:粉丝都疯了!

    一.EDG夺冠信息 11月6日,在英雄联盟总决赛中,EDG战队以3:2战胜韩国队,获得2021年英雄联盟全球总决赛冠军,这个比赛在全网各大平台也是备受瞩目: 1.微博热搜第一名,截止2021-11-1 ...

  5. Python基础(range)

    arr = [1,2,3,4,5,6,7,8,9] for i in range(0,len(arr),2): print(arr[i],end=' | ') brr = arr[0:len(arr) ...

  6. Linux(kali)基础设置

    本笔记的友情链接 常用目录介绍 boot 存放启动文件 dev 存放设备文件 etc 存放配置文件 home 普通用户家目录,以/home/$username的方式存放 media 移动存储自动挂载目 ...

  7. dart系列之:在dart中使用生成器

    目录 简介 两种返回类型的generator Stream的操作 总结 简介 ES6中在引入异步编程的同时,也引入了Generators,通过yield关键词来生成对应的数据.同样的dart也有yie ...

  8. 一个没被spring管理的类怎么创建对象并使用里面的方法

    一个对象new出来的,如果不是构造器注入@Data 也不好使啊,尝试构造器注入一下,或者set进去 第二次尝试使用这个. 向这种只能构造器注入或者通过上面的set方法来注入了,component是不好 ...

  9. Ubuntu 18.04.5 LTS Ceph集群之 cephx 认证及使用普通用户挂载RBD和CephFS

    1.cephx认证和授权 1.1 CephX认证机制 Ceph使用cephx协议对客户端进行身份认证: 1.每个MON都可以对客户端进行身份验正并分发密钥, 不存在单点故障和性能瓶颈 2. MON会返 ...

  10. Codeforces 1290D - Coffee Varieties(分块暴力+完全图的链覆盖)

    Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 发现自己交互题烂得跟 s ...