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

  • 相关阅读:
    Uboot启动流程分析(四)
    git更新提交到仓库
    MSM8953通过ADB进行AT指令操作
    Uboot启动流程分析(五)
    去除字符串中多个空格,保留一个空格
    socket握手SYN和ACK理解
    Redhat6更改yum源 (转)
    form提供的两种数据传输方式 get和post method=”post“和method=”get”
    linux误删除恢复(未验证)
    web前端学习路线
  • 原文地址:https://www.cnblogs.com/dishengAndziyu/p/10916370.html
Copyright © 2020-2023  润新知