Multiple Inheritance in C++
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++的更多相关文章
- Multiple inheritance in Go
原文:http://golangtutorials.blogspot.com/2011/06/multiple-inheritance-in-go.html --------------------- ...
- 面向对象程序设计-C++ Inheritance & Multiple inheritance & RTTI【第十三次上课笔记】
Sadly, 这节课带过去的笔记本没电了 T^T 导致没有一行 Code, Sorry 笔记如下: Shape * p1; //使用指针创建对象的方法 p = new Circle (2.0); Sh ...
- 条款40:明智而审慎地使用多重继承(use multiple inheritance judiciously)
NOTE: 1.多重继承比单一继承复杂.它可能导致新的歧义性,以及对virtual继承的需要. 2.virtual 继承会增加大小 速度 初始化(及赋值)复杂度等等成本.如果virtual base ...
- Memory Layout for Multiple and Virtual Inheritance
Memory Layout for Multiple and Virtual Inheritance(By Edsko de Vries, January 2006)Warning. This art ...
- JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance
// the parent constructor function Parent(name) { this.name = name || 'Adam'; } // adding functional ...
- [置顶] c++类的继承(inheritance)
在C++中,所谓"继承"就是在一个已存在的类的基础上建立一个新的类.已存在的类(例如"马")称为"基类(base class )"或&quo ...
- Classical Inheritance in JavaScript
JavaScript is a class-free, object-oriented language, and as such, it uses prototypal inheritance in ...
- (转) Friendship and inheritance
原地址: http://www.cplusplus.com/doc/tutorial/inheritance/ Friend functions In principle, private and p ...
- <Effective C++>读书摘要--Inheritance and Object-Oriented Design<二>
<Item 36> Never redefine an inherited non-virtual function 1.如下代码通过不同指针调用同一个对象的同一个函数会产生不同的行为Th ...
随机推荐
- loadrunner12自带的机票预订服务,解决httpd: Could not reliably determine the server's fully qualified domain name 问题
遇到以上问题是在启动loadrunner12自带的机票预订服务器情况下遇到的,错误提示如下图: 解决方案: 编辑httpd.conf 文件,加入一句 ServerName localhost:1080 ...
- 问题 L: Yougth的最大化
题目描述 Yougth现在有n个物品的重量和价值分别是Wi和Vi,你能帮他从中选出k个物品使得单位重量的价值最大吗? 输入 有多组测试数据 每组测试数据第一行有两个数n和k,接下来一行有n个数Wi和V ...
- 网页视频不能自动播放?HTML5 video报错Uncaught (in promise) DOMException解决方法
话说发哥四年前写了一个网页,如上图效果,实际网址http://pano.z01.com ,话说做好时是正常的,突然某一天,客户说你这个网站动画不见了,这是什么原因? 结果检查脚本一切正常. 其实也不是 ...
- pytest-mian函数运行
1.设置多并发运行 1.命令行安装 pip install pytest-xdist #安装插件,进行多并发运行,#调用:-n -5 import pytest # pytest.main([&quo ...
- ES6--ES12笔记整理(1)
一.let const 五个共同特点 不允许重复声明 块级作用域 不存在变量提升 不影响作用域链 暂时性死区---在代码块内,使用let/const命令声明变量之前,该变量都是不可用的.这在语法上,称 ...
- vue3 学习笔记 (四)——vue3 setup() 高级用法
本篇文章干货较多,建议收藏! 从 vue2 升级到 vue3,vue3 是可以兼容 vue2 的,所以 vue3 可以采用 vue2 的选项式API.由于选项式API一个变量存在于多处,如果出现问题时 ...
- vue3 学习笔记 (五)——vue3 的 setup 如何实现响应式功能?
setup 是用来写组合式 api ,内部的数据和方法需要通过 return 之后,模板才能使用.在之前 vue2 中,data 返回的数据,可以直接进行双向绑定使用,如果我们把 setup 中数据类 ...
- [cf1361E]James and the Chase
称一个点是"好点",当且仅当其到其余所有点恰存在一条简单路径 结论1:$x$为好点当且仅当以$x$为根的dfs树包含所有点且非树边均为返祖边 若不包含所有点,那么$x$到不被包含的 ...
- [bzoj1863]皇帝的烦恼
二分枚举答案,假设是ans,考虑判定答案从前往后计算,算出每一个将军与第一个将军最少和最多有多少个相同的奖牌,贪心转移即可 1 #include<bits/stdc++.h> 2 usin ...
- Sentry 监控 - Snuba 数据中台架构(编写和测试 Snuba 查询)
系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...