zoukankan      html  css  js  c++  java
  • Cpp多重继承会产生的问题

    多重继承常常被认为是 OOP 中一种复杂且不必要的部分。多重继承面临 crash 的场景并非难以想象,来看下面的例子。

    1. 名称冲突

    来看以下情况:

    image

    如果 Dog 类以及 Bird 类都有一个名为 eat() 的方法,而子类又没有 override 该方法。如果此时调用子类的 eat() 方法,编译器就会报错,指出 eat() 的调用有歧义(不知道是调用从 Dog 类继承而来的 eat() 方法,还是从 Bird 类继承而来的 eat() 方法)。代码如下:

    class Dog
    {
    public:
        virtual void eat() {};
    };
    
    class Bird
    {
    public:
        virtual void eat() {};
    };
    
    class DogBird : public Dog, public Bird
    {
    
    };
    
    int main()
    {
        DogBird db;
        db.eat(); // BUG! Ambiguous call to method eat()
        return 0;
    }
    
    /*
    编译错误:
    [purple@archlinux AAA]$ clang++ aa.cc
    aa.cc:21:8: error: member 'eat' found in multiple base classes of different types
        db.eat(); // BUG! Ambiguous call to method eat()
           ^
    aa.cc:4:18: note: member found by ambiguous name lookup
        virtual void eat() {};
                     ^
    aa.cc:10:18: note: member found by ambiguous name lookup
        virtual void eat() {};
                     ^
    1 error generated.
    */

    解决方法:

    #include <iostream>
    using namespace std;
    
    class Dog
    {
    public:
        virtual void eat() {cout << "The Dog has eaten." << endl;};
    };
    
    class Bird
    {
    public:
        virtual void eat() {cout << "The Bird has eaten." << endl;};
    };
    
    class DogBird : public Dog, public Bird
    {
    
    };
    
    int main()
    {
        DogBird db;
        static_cast<Dog>(db).eat(); // Slices, calling Dog::eat()
        db.Bird::eat();             // Calls Bird::eat()
        return 0;
    }
    
    /*
    Output:
    The Dog has eaten.
    The Bird has eaten.
    */
    为了消除歧义,要么在 DogBird类重写 eat() 方法,要么显示的指明调用的是哪一个父类的版本。

    2. 歧义基类

    来看以下情况:

    image

    虽然可能产生 name ambiguity,但是 C++ 允许这种类型的类层次结构。例如,如果 Animal 类有一个 public 方法 sleep(),那么 DogBird 对象将无法调用这个方法,因为编译器不知道调用 Dog 继承的版本还是 Bird 继承的版本。代码如下:

    class Animal
    {
    public:
        void sleep(){}
    };
    
    class Dog : public Animal
    {
    };
    
    class Bird : public Animal
    {
    };
    
    class DogBird : public Dog, public Bird
    {
    };
    
    int main()
    {
        DogBird db;
        db.sleep();
        return 0;
    }
    
    /*
    发生编译错误
    
    [purple@archlinux ~]$ clang++ aa.cc
    aa.cc:25:8: error: non-static member 'sleep' found in multiple base-class subobjects of type 'Animal':
        class DogBird -> class Dog -> class Animal
        class DogBird -> class Bird -> class Animal
        db.sleep();
           ^
    aa.cc:7:10: note: member found by ambiguous name lookup
        void sleep(){}
             ^
    1 error generated.
    */

    使用“菱形”类层次结构的最佳方法是将最顶部的类设置为抽象类,所有方法都设置为纯虚方法。由于类只声明方法而不提供定义,在基类中没有方法可以调用,因此在这个层次上就不会产生歧义。代码如下:

    #include <iostream>
    using namespace std;
    
    class Animal
    {
    public:
        virtual void sleep() = 0;
    };
    
    class Dog : public Animal
    {
    public:
        virtual void sleep()
        {
            cout << "Dog sleep!" << endl;
        }
    };
    
    class Bird : public Animal
    {
    public:
        virtual void sleep()
        {
            cout << "Bird sleep!" << endl;
        }
    };
    
    class DogBird : public Dog, public Bird
    {
    public:
        // 注意:虽然从语法上来说,DogBird可以不override sleep方法
        // 但是如此一来,再调用DogBird类的sleep方法时,会分不清是Dog类的还是Bird类的
        virtual void sleep()
        {
            cout << "DogBird sleep!" << endl;
        }
    };
    
    int main()
    {
        DogBird db;
        db.sleep();
        return 0;
    }
    
    /*
    Output:
    DogBird sleep!
    */

    小结

    我们往往会在定义一个“既是一个事物同时又是另外一个事物”的情况下使用多重继承,然而,实际上遵循这个模式的实际对象很难恰如其分的转换为合适的代码,因此在工程中,我们要尽量避免使用多重继承。

  • 相关阅读:
    用java开发图形界面项目,如何实现从本地选择图片文件并以二进制流的形式保存到MySQL数据库,并重新现实到面板
    算法练习LeetCode初级算法之数组
    算法练习LeetCode初级算法之字符串
    算法练习LeetCode初级算法之排序和搜索
    20169221 201620172 《网络攻防实践》第四周学习总结
    20169221 201620172 《网络攻防》 第三周学习总结
    20169221 201620172 《移动平台应用开发》 第二周学习总结
    20169221 201620172 《移动平台开发时间》 第一周学习总结
    20169221 201620172 《网络攻防实践》 第二周学习总结
    20169221 201620172 《移动平台开发时间》 第三周学习总结
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/4396035.html
Copyright © 2011-2022 走看看