C++中的多重继承(二)

1,本文分析另一个多重继承问题及其工程中的解决方案,单继承加多接口实现的开发方式;

2,多重继承的问题三:

1,多重继承可能产生多个虚函数表:

1,实际工程中可能造成不可思议的问题,并且这些问题很难以查找和排除;

3,多重继承问题三编程实验:

 1 #include <iostream>
 2 #include <string>
 3
 4 using namespace std;
 5
 6 class BaseA
 7 {
 8 public:
 9     virtual void funcA()
10     {
11         cout << "BaseA::funcA()" << endl;
12     }
13 };
14
15 class BaseB
16 {
17 public:
18     virtual void funcB()
19     {
20         cout << "BaseB::funcB()" << endl;
21     }
22 };
23
24 class Derived : public BaseA, public BaseB
25 {
26
27 };
28
29 int main()
30 {
31     Derived d;
32     BaseA* pa = &d;
33     BaseB* pb = &d;
34     BaseB* pbe = (BaseB*)pa;    // 忘记这种转换方式
35     BaseB* pbc = dynamic_cast<BaseB*>(pa);    // 用这种转换方式
36
37     cout << "sizeof(d) = " << sizeof(d) << endl;  // 这是虚函数表指针定义的;
38
39     cout << "Using pa to call funcA()..." << endl;
40
41     pa->funcA();  // BaseA::funcA()
42
43     cout << "Using pb to call funcB()..." << endl;
44
45     pb->funcB();  // BaseB::funcB()
46
47     cout << "Using pbe to call funcB()..." << endl;
48
49     pbe->funcB(); // BaseB::funcA()  pa 和 pb 都指向同一个对象,但是保存的值不一样,具体见 4 中分析;
50
51     cout << "Using pbc to call funcB()..." << endl;
52
53     pbc->funcB();  // BaseB::funcb()  // 使用了 dynamic_cast,编译器就会检查 pa 指向的指针是 d 对象,进而检查d 对象有 BaseA 和 BaseB,进而认为这里转换合法,并且对指针有个修正,使得pbb 指向 pb 的位置,则调用正确;
54
55     cout << endl;
56
57     cout << "pa = " << pa << endl;  // 0xbfd11238
58     cout << "pb = " << pb << endl;  // 0xbfd1123c
59     cout << "pbe = " << pbe << endl;  // 0xbfd11238  没有修正
60     cout << "pbc = " << pbc << endl;  // 0xbfd1123c;做了修正
61
62     return 0;
63 }

1,如果说碰上需要强制类型转换的场合,并且需要强制类型转换的是类,然后类里面又定义了虚函数,然后就是推荐使用 dynamic_cast;

4,需要进行强制类型转换时,C++ 中推荐使用新式类型转换关键字;

1,解决方案:dynamic_cast;

2,示意图:

1,pa 和 pb 都指向同一个对象,但是保存的值不一样;

2,pbb 指针指向了 pa 的虚函数表指针,所以调用了 pa 中的函数 funcB();

3,在与继承、虚函数相关的强制类型转换时,用 danamic_cast;

5,工程开发中的“多重继承”方式:

1,单继承某个类 + 实现(多个)接口;

2,示意图:

1,这是面向对象理论中所推荐的方式,实际工程开发过程中,只使用单继承;

2,单继承不可能描述生活中所有的情形,因此可以使用单继承+多接口;

3,Derived 直接继承 Base 类,然后自身实现多个接口;

6,正确的多继承方式编程实验:

 1 #include <iostream>
 2 #include <string>
 3
 4 using namespace std;
 5
 6 class Base
 7 {
 8 protected:
 9     int mi;
10
11 public:
12     Base(int i)
13     {
14         mi = i;
15     }
16
17     int getI()
18     {
19         return mi;
20     }
21
22     /* 在顶层父类中,定义函数判断参数指针指向的是不是当前对象(用法见 main() 函数),解决多重继承的问题一 */
23     bool equal(Base* obj)  // 传递的指针要加上 dynamic_cast 强制类型转换;
24     {
25         return (this == obj);
26     }
27 };
28
29 /* 加减接口 */
30 class Interface1
31 {
32 public:
33     virtual void add(int i) = 0;
34     virtual void minus(int i) = 0;
35 };
36
37 /* 乘除接口 */
38 class Interface2
39 {
40 public:
41     virtual void multiply(int i) = 0;
42     virtual void divide(int i) = 0;
43 };
44
45 /* 单继承、实现多个接口 */
46 class Derived : public Base, public Interface1, public Interface2  // 表象上依然是 C++ 中的多继承,但是整个程序的语义上来看是单继承加上实现多个接口;
47 {
48 public:
49     Derived(int i) : Base(i)
50     {
51     }
52
53     void add(int i)  // 实现接口中的加法
54     {
55         mi += i;
56     }
57
58     void minus(int i)  // 实现接口中的加法
59     {
60         mi -= i;
61     }
62
63     void multiply(int i)  // 实现接口中的加法
64     {
65         mi *= i;
66     }
67
68     void divide(int i)  // 实现接口中的加法
69     {
70         if( i != 0 )
71         {
72             mi /= i;
73         }
74     }
75 };
76
77 int main()
78 {
79     Derived d(100);
80     Derived* p = &d;
81     Interface1* pInt1 = &d;
82     Interface2* pInt2 = &d;
83
84     cout << "p->getI() = " << p->getI() << endl;    // 100
85
86     pInt1->add(10);
87     pInt2->divide(11);
88     pInt1->minus(5);
89     pInt2->multiply(8);
90
91     cout << "p->getI() = " << p->getI() << endl;    // 40
92
93     cout << endl;
94
95     cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) <<     endl;  // 打印 1,不转换则报错,没有这样的函数可以调用
96     cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) <<     endl;  // 打印 1,不转换则报错,没有这样的函数可以调用
97
98     return 0;
99 }

7,正确的使用多重继承:

1,一些有用的工程建议:

1,先继承自一个父类,然后实现多个接口;

1,接口不是一个完整类实现,仅仅定义了公有函数原型而已;

2,父类中提供 equal() 成员函数;

3,equal() 成员函数用于判断指针是否指向当前对象;

4,与多重继承相关的强制类型转换用 dynamic_cast 完成;

8,小结:

1,多继承中可能出现多个虚函数表指针;

2,与多重继承相关的强制类型转换用 dynamic_cast 完成;

1,对指针的值进行一定的修正;

3,工程开发中采用“单继承多接口”的方式使用多继承;

1,仅仅在表象上是多继承,面向对象语义上不是多继承,因为仅仅继承了一个类,其它的类都是接口;

4,父类提供成员函数用于判断指针是否指向当前对象;

原文地址:https://www.cnblogs.com/dishengAndziyu/p/10916370.html

时间: 2024-10-11 11:46:58

C++中的多重继承(二)的相关文章

二叉树进阶之寻找一棵二叉树中的最大二叉搜索子树

转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6618915.html  (规律:在二叉树中寻找某性质的,都应该以递归思维:从根结点开始递归左右,一直到底,由底向上返回的信息来判断当前结点.求当前结点.即:二叉树的题目,从下往上想,递归的返回过程就是从下往上由叶到根建立二叉树的过程,在此过程中对每一步的"根"结点作性质判断,返回到根时即是整棵树的性质判断了) 从一棵树中寻找结点数最多的二叉搜索子树,并返回这棵子树的头结点. 从题目我们知道以下要求

Jquery:Jquery中的事件&lt;二&gt;

这几天快忙死了,办了离职还得办入职,完全打乱了我的计划,但是能有一个理想的工作,还是很开心的,以后加把劲,争取把计划再赶上来!不说了,学习!!! 五.事件对象的属性 1.event.type:获取事件的类型,其中event是事件的对象. 2.event.preventDefaule(),在上一个学习笔记中已经有介绍了,该方法是阻止默认的事件事件行为.event.stopPropagation(),该方法的作业是阻止事件的冒泡. 3.event.target,它的作用是获取到触发事件的元素.通过返

掌握JS中的“this” (二)

在上一篇文章 掌握JS中的"this" (一) 里面, 我们学会了如何正确使用JavaScript中的 this 关键字及其基本原理.我们也知道决定 this 指向哪个对象的关键因素, 是找出当前的执行上下文(execution context).但如果执行上下文不按正常的方式进行设置,问题可能就会变得很棘手.在本文中,我会着重提示在哪些地方会发生这种情况, 以及用什么方式可以弥补. 解决常见问题 在本节中,我们将探讨一些使用 this 关键字时最常见的问题, 并了解如何处理这种情况.

19.把1~100存到二维数组a[10][10]中,并按二维矩阵形式输出

#include<iostream>using namespace std; int main(){    int a[10][10];    for(int i=0;i<10;i++)    {        for(int j=0;j<10;j++)        {            a[i][j]=i*10+j+1;//二维数组逻辑上还是一维数组的存储方式        }    }    for(int j=0;j<10;j++)    {        for

java 中的多重继承

Java中的接口不仅仅是一种更纯粹的抽象类,它的目标比这更高.因为接口是根本没有任具体实现的.也就是说,没有任何与接口相关的存储:因此,也就无法阻止多个接口的组合.这一点是很有价值的,因为你有时候需要去表示"一个X是一个a和一个b以及一个c".在C++中,组合多个类的接口的行为被称作为多重继承.它可能会使你背负很沉重的包袱,因为每个类都有一个具体实现.在java中,你可以执行相同的行为,但是只有一个类可以有具体的实现:因此通过组合多个接口,c++的问题不会在java中发生: 下面展示一

Golang中使用log(二):Golang 标准库log的实现

前一篇文章我们看到了Golang标准库中log模块的使用,那么它是如何实现的呢?下面我从log.Logger开始逐步分析其实现. 其源码可以参考官方地址 1.Logger结构 首先来看下类型Logger的定义: type Logger struct { mu sync.Mutex // ensures atomic writes; protects the following fields prefix string // prefix to write at beginning of each

C++中的异常处理(二)

C++中的异常处理(二) 标签: c++C++异常处理 2012-11-24 20:56 1713人阅读 评论(2) 收藏 举报  分类: C++编程语言(24)  版权声明:本文为博主原创文章,未经博主允许不得转载. 先看下面的代码: [cpp] view plain copy int main() { int *i=new int(10); /* 这中间的代码出现异常 */ delete i; return 0; } 如果出现了这样的情况,动态分配的内存就不会被释放.为了处理这样的问题,可以

【编程题目】求一个矩阵中最大的二维矩阵(元素和最大)

35.(矩阵)求一个矩阵中最大的二维矩阵(元素和最大).如:1 2 0 3 42 3 4 5 11 1 5 3 0中最大的是:4 55 3要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 早上灭小题! /* 35.(矩阵) 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 0 3 4 2 3 4 5 1 1 1 5 3 0 中最大的是: 4 5 5 3 要求:(1)写出算法;(2)分析时间复杂度;(3)用 C 写出关键代码 */ #include <stdio.h>

IT公司100题-35- 求一个矩阵中最大的二维矩阵(元素和最大)

问题描述: 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 中最大的是: 4 5 9 10 分析: 2*2子数组的最大和.遍历求和,时间复杂度为O(mn). 代码实现: 1 // 35.cc 2 #include <iostream> 3 #include <climits> 4 using namespace std; 5 6 int find_max(int (*a)[5], int m, int n) { 7 in