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,父类提供成员函数用于判断指针是否指向当前对象;