zoukankan      html  css  js  c++  java
  • 【转载】 C++多继承中重写不同基类中相同原型的虚函数

    本篇随笔为转载,原文地址: C++多继承中重写不同基类中相同原型的虚函数

    在C++多继承体系当中,在派生类中可以重写不同基类中的虚函数。下面就是一个例子:

    1. class CBaseA
    2. {
    3. public:
    4.     virtual void TestA();
    5. };
    6. class CBaseB
    7. {
    8. public:
    9.     virtual void TestB();
    10. };
    11. class CDerived : public CBaseA, public CBaseB
    12. {
    13. public:
    14.     virtual void TestA(); // 重写基类CBaseA中的虚函数TestA()
    15.     virtual void TestB(); // 重写基类CBaseB中的虚函数TestB()
    16. };
    17. void Test()
    18. {
    19.     CDerived D;
    20.     CBaseA *pA = &D;
    21.     CBaseB *pB = &D;
    22.     pA->TestA(); // 调用类CDerived的TestA()函数
    23.     pB->TestB(); // 调用类CDerived的TestB()函数
    24. }

        可是,如果两个基类中有一个相同原型的虚函数,例如下面这样:

    1. class CBaseA
    2. {
    3. public:
    4.     virtual void Test();
    5. };
    6. class CBaseB
    7. {
    8. public:
    9.     virtual void Test();
    10. };

        怎样在派生类中重写这两个相同原型的虚函数呢?
        也许这种情况并不常见,可是这种情况却确实存在。比如说开发的时候使用的两个类库是不同的厂商提供的,或者说这两个类库是由公司的不同开发小组开发的。对前者来说,修改基类的接口是不可能的;对后者来说,修改接口的代价很大。
        如果在派生类中直接重写这个虚函数,那么2个基类的Test()虚函数都将被覆盖。这样的话就只能有一个Test()的实现,而不是像前面的例子那样有不同的实现。

    1. class CDerived : public CBaseA, public CBaseB
    2. {
    3. public:
    4.     virtual void Test();
    5. };
    6. void Test()
    7. {
    8.     CDerived D;
    9.     CBaseA *pA = &D;
    10.     CBaseB *pB = &D;
    11.     // 下面2行代码都将调用类CDerived的Test()函数
    12.     pA->Test();
    13.     pB->Test(); 
    14. }

        为了实现第一个例子中的那样,在派生类CDerived中重写不同基类中相同原型的虚函数Test(),可以使用下面的方法。
        首先,不需要对2个基类进行任何修改(在实际的开发当中,修改基类的可能性非常小)。

    1. class CBaseA
    2. {
    3. public:
    4.     virtual void Test();
    5. };
    6. class CBaseB
    7. {
    8. public:
    9.     virtual void Test();
    10. };

        现在,为这个继承体系添加2个中间类,分别从2个基类派生。

    1. class CMiddleBaseA : public CBaseA
    2. {
    3. private:
    4.     // 真正的实现函数
    5.     // 设置为纯虚函数,在派生类里必须实现
    6.     virtual void CBaseA_Test() = 0;
    7.     // 改写继承下来的虚函数
    8.     // 仅仅直接调用真正的实现函数
    9.     virtual void Test() 
    10.     { 
    11.         CBaseA_Test(); 
    12.     }
    13. };
    14. // 与类CMiddleBaseA采用相同的方法
    15. class CMiddleBaseB : public CBaseB
    16. {
    17. private:
    18.     virtual void CBaseB_Test() = 0;
    19.     virtual void Test() 
    20.     { 
    21.         CBaseB_Test(); 
    22.     }
    23. };

        然后,类CDerived以上面2个中间类作为基类来派生。分别重写上面2个基类中原型不同的纯虚函数,添加不同的实现代码。

    1. class CDerived : public CMiddleBaseA, public CMiddleBaseB
    2. {
    3. private:
    4.     // 重写从中间类继承下来的虚函数
    5.     virtual void CBaseA_Test(); // 这里实际上是重写CBaseA的Test()
    6.     virtual void CBaseB_Test(); // 这里实际上是重写CBaseB的Test()
    7. };
    8. void Test()
    9. {
    10.     CDerived D;
    11.     CBaseA *pA = &D;
    12.     CBaseB *pB = &D;
    13.     // 调用类CBaseA的Test()函数
    14.     // 由于C++多态的特性,实际上调用的是类CDervied中的CBaseA_Test()函数
    15.     pA->Test(); 
    16.     // 调用类CBaseB的Test()函数
    17.     // 由于C++多态的特性,实际上调用的是类CDervied中的CBaseB_Test()函数
    18.     pB->Test();
    19. }

        现在以上面代码中的pA->Test();这行代码来说明上面的方案是怎么实现的。
        首先,由于虚函数Test()在类CBaseA的派生类CMiddleBaseA中被重写,所以这行代码会去调用类CMiddleBaseA的Test()函数;
        然后,类CMiddleBaseA的Test()函数会去调用实现函数CBaseA_Test();
        最后,由于虚函数CBaseA_Test()在类CMiddleBaseA的派生类CDerived中被重写,所以真正调用的是类CDerived中的CBaseA_Test()函数。
        同样的道理,代码pB->Test();实际上调用的是类CDervied中的CBaseB_Test()函数。


        通过上面的方法就可以在C++多继承中重写不同基类中相同原型的虚函数。

  • 相关阅读:
    POJ 3268 Silver Cow Party (Dijkstra)
    怒学三算法 POJ 2387 Til the Cows Come Home (Bellman_Ford || Dijkstra || SPFA)
    CF Amr and Music (贪心)
    CF Amr and Pins (数学)
    POJ 3253 Fence Repair (贪心)
    POJ 3069 Saruman's Army(贪心)
    POJ 3617 Best Cow Line (贪心)
    CF Anya and Ghosts (贪心)
    CF Fox And Names (拓扑排序)
    mysql8.0的新特性
  • 原文地址:https://www.cnblogs.com/niuxichuan/p/6241461.html
Copyright © 2011-2022 走看看