我没有C ++经验,而且我来自Java背景。最近,我在接受采访时被问到为什么Java不允许多重继承,答案很简单。但是,我仍然很好奇C ++如何处理它,因为它允许你从多个类继承。
具体来说,假设有一个名为MechanicalEngineer
的类,另一个名为ElectricalEngineer
。两者都有一个名为buildRobot()
的方法。
如果我们制作第三个班级RoboticsEngineer
会发生什么,这两个班级从两者中都有,并且不会覆盖该方法,您只需致电:
(some instance of RoboticsEngineer).buildRobot()
是否会抛出异常,或者是否会使用其中一个超类的方法?如果是这样,编译器如何知道要使用哪个类?
答案 0 :(得分:21)
编译器会将此类情况(即,尝试调用(some instance of RoboticsEngineer).buildRobot()
)标记为错误。
这是因为派生对象内部有两个基础对象(一个MechanicalEngineer
实例和一个ElectricalEngineer
实例)的副本,而单独的方法签名不足以告诉哪一个使用
如果您覆盖buildRobot
中的RoboticsEngineer
,则可以通过为类名添加前缀来明确说明要使用的继承方法,例如:
void RoboticsEngineer::buildRobot() {
ElectricalEngineer::buildRobot()
}
通过相同的硬币,您实际上可以“强制”编译器使用buildRobot
的一个版本或另一个版本,方法是在其前面添加类名:
(some instance of RoboticsEngineer).ElectricalEngineer::buildRobot();
在这种情况下,将调用方法的ElectricalEngineer
实现,没有歧义。
如果Engineer
和MechanicalEngineer
都有ElectricalEngineer
基类,并且在两种情况下都指定继承为virtual
,则会给出一个特殊情况。使用virtual
时,派生对象不包含两个Engineer
实例,但编译器确保只有一个实例。 class Engineer {
void buildRobot();
};
class MechanicalEngineer: public virtual Engineer {
};
class ElectricalEngineer: public virtual Engineer {
};
。这看起来像这样:
(some instance of RoboticsEngineer).buildRobot();
在这种情况下,
virtual
将毫不含糊地解决。如果buildRobot声明为buildRobot
并在两个派生类之一中重写,则情况也是如此。无论如何,如果两个派生类(ElectricalEngineer和MechanicalEngineer)都覆盖(some instance of RoboticsEngineer).buildRobot();
,则会再次出现歧义,并且编译器会将调用{{1}}的尝试标记为错误。
答案 1 :(得分:5)
它没有处理它。这是模棱两可的。 error C2385: ambiguous access of 'functionName'
编译器很聪明,知道它不应该猜测你的意思
对于要编译的程序,您需要告诉编译器:
答:你知道这是一个有问题的问题
B.告诉它究竟是什么意思。
为此,您需要明确告诉编译器您要求的方法:
RoboticsEngineer myRobot;
myRobot.ElectricalEngineer::buildRobot();
答案 2 :(得分:0)
编译器会抱怨这种情况。
在这种情况下,c ++建议使用“纯虚拟”方法buildRobot()函数创建一个接口。 MechanicalEngineer和EletricalEnginner将继承Interface并覆盖buildRoboot()函数。
当您创建RoboticsEnginner对象并调用buildRobot()函数时,将调用该接口的函数。
答案 3 :(得分:0)
struct MecEngineer {
void buildRobot() { /* .... */ }
};
struct EleEngineer {
void buildRobot() { /* .... */ }
};
struct RoboticsEngineer : MecEngineer, EleEngineer {
};
现在,当你这样做时,
robEngObject -> buildRobot() ;
这样的调用无法解决且不明确,因为两个子对象都具有相同签名的成员函数,并且编译器不知道要调用哪个。在这种情况下,您需要使用::
运算符或使用static_cast
明确提及它。
static_cast<MecEngineer*> (robEngObject) -> buildRobot() ;
答案 4 :(得分:0)
没有任何关于允许这种情况的多类继承。 Java会产生与接口相同的问题。
public interface A {
public void doStuff();
}
public interface B {
public void doStuff();
}
public class C implements A, B {}
简单的答案是编译器会抛出错误。