防止C++中的多重继承

prevent multiple inheritance in C++

本文关键字:多重继承 C++ 防止      更新时间:2023-10-16

最近我参加了一次C++技术面试:在面试中,面试官问了我一个我无法回答的问题:即使我在互联网和一些论坛上尝试过,但都无法得到答案,请参阅下面的代码片段:

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:派生类:public Base1//Ok。--->无错误
  • Scenerio 2:派生类:public Base2//好。--->无错误
  • Scenerio 3:派生类:public Base1,public Base2//错误或异常或其他任何情况。无法继承

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

谢谢。

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

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"的声明

您可以使用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; }

只有从Base1继承或从Base2继承时,它才能工作和编译。如果您尝试从两者继承,它不会编译。如果您想要一个运行时错误,而不是编译时错误,您甚至可以使用相同的方法来检查。试着播放这个片段。

运行时检查:

#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的好主意。不过,它的好处是不引入虚拟功能。

使用赖建议的方法,但为Base0提供一个必须由Base1和Base2重写的纯虚拟函数。如果您试图同时从Base1和Base2继承,编译器应该抱怨函数不明确。编辑:这不是Mike在下面指出的正确答案

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

class Base1 : public Base0
class Base2 : public Base0

然后,如果用户试图同时从Base1Base2继承,编译器就会抱怨。