防止C ++中的多重继承

时间:2013-12-19 08:24:42

标签: c++ inheritance multiple-inheritance

最近我参加了一次C ++技术访谈:在那期间,面试官问我一个我无法回答的问题:即使我尝试上网和一些论坛但无法得到答案,请参阅下面的代码片段:< / p>

using namespace std;

class Base1
{
    public:
    Base1() 
    {
        cout << "Base1 constructor..." << endl;
    }

    ~Base1() 
    {
        cout << "Base1 Destructor..." << endl;
    }
};  

class Base2
{
public:
    Base2() 
    {
        cout << "Base2 constructor..." << endl;
    }

    ~Base2() 
    {
      cout << "Base2 Destructor..." << endl;  
    }
};

class Derived : public Base1, public Base2 
{
public:
  Derived()
  {
      cout << "Derived constructor...."  << endl;
  }
  ~Derived()
  {
      cout << "Derived Destructor..." << endl;
   }
};


int main()
{
   cout << "Hello World" << endl; 
   Base1 b1; Base2 b2;
   Derived d1;

   return 0;
}

描述:有两个名为Base1和Base2的基类和一个名为Derived的派生类。派生是从Base1和Base2继承的多重。

问题:我希望Derived只能从一个类继承而不是从两个类继承。如果开发人员将尝试从这两个类继承:那么错误应该生成:让我总结一下:

  • Scenerio 1:class Derived:public Base1 // Ok .---&gt;没有错误
  • Scenerio 2:class Derived:public Base2 // Ok .---&gt;没有错误
  • Scenerio 3:class Derived:public Base1,public Base2 //错误或异常或其他任何内容。无法继承。

注意:你能回答这个问题:我真的不确定这是否可行。还有一件事:这不是钻石问题。

感谢。

5 个答案:

答案 0 :(得分:28)

在两个具有不同返回类型的基础中声明纯虚函数:

class B1 {
   virtual void a() = 0;
};

class B2 {
   virtual int a() = 0; // note the different return type
};

无法从两者继承。

class D : public B1, public B2 {
public:
    // virtual void a() {} // can't implement void a() when int a() is declared and vice versa
    virtual int  a() {}
};

int main(void) {
    D d; // produces C2555 error
    return 0;
}

产生此错误:

  • 错误C2555:'D :: a':覆盖虚函数返回类型与'B1 :: a'不一致且不协变
  • 见'B1 :: a'
  • 的声明

答案 1 :(得分:3)

您可以使用C ++ 11执行此操作,请查看:

#include <type_traits>
struct Base1 {}; 
struct Base2 {}; 

struct Derived 
   : public Base1
  , public Base2
{ 
  Derived() 
  { 
     static_assert( !(std::is_base_of< Base1, Derived >::value && std::is_base_of< Base2, Derived >:: value), "You cannot inherit from both Base1 and Base2" ); 
  } 
}; 



int main() { Derived d; return 0; }

仅当您从Base2继承Base1 时,它才能工作和编译。 如果您尝试从两者继承,则不会编译。 如果您想要运行时错误,而不是编译时错误,您甚至可以使用相同的方法来检查它。尝试使用此代码段。

答案 2 :(得分:2)

运行时检查:

#include <iostream>
#include <stdexcept>
#include <typeinfo>

class B1 {
    protected:
    template <typename D>
    B1(D* d) {
        // The paranoid 'is_same' is preventing the cast (B1*)this in the derived constructor.
        if((void*)this != (void*)d || std::is_same< B1, D >::value)
            throw std::logic_error("Multiple Inheritance [1]");
    }

    int data;
};

class B2 {
    protected:
    template <typename D>
    B2(D* d) {
        // The paranoid 'is_same' is preventing the cast (B2*)this in the derived constructor.
        if((void*)this != (void*)d || std::is_same< B2, D >::value)
            throw std::logic_error("Multiple Inheritance [2]");
    }

    int data;
};


struct D : public B1, public B2 {
    D()
    :   B1(this), B2(this)
    {}
};

int main() {
    D d;
}

注意:如果类为空,则不起作用。 不如@egur的优秀想法那么好。 但它具有不引入虚拟功能的好处。

答案 3 :(得分:0)

使用Lai Yu-Hsuan建议的方法,但给Base0一个必须由Base1和Base2覆盖的纯虚函数。如果您尝试从Base1和Base2继承,编译器应该抱怨模糊函数。 编辑:这不是Mike下面指出的正确答案

答案 4 :(得分:-1)

我能弄清楚的唯一方法是强迫这种情况成为钻石问题。

class Base1 : public Base0
class Base2 : public Base0

然后,如果用户尝试从Base1Base2继承,编译器会抱怨。