2011-07-20 123 views
21

我没有C++的经验,我来自Java背景。最近,我在一次采访中被问及为什么Java不允许多重继承,答案很简单。不过,我仍然对C++如何处理它感到好奇,因为它允许你从多个类继承。多个超类的多继承,C++和相同方法签名

具体来说,就是说有一个叫MechanicalEngineer的类,另一个叫ElectricalEngineer。两者都有一个名为buildRobot()的方法。

如果我们把第三类RoboticsEngineer会发生什么,来自两个inherets并不会覆盖方法,你只要致电:

(some instance of RoboticsEngineer).buildRobot() 

会抛出异常,或者从一个方法超类将被使用?如果是这样,编译器如何知道使用哪个类?

+4

如果一个类有一个方法'buildRobot'并且一个接口有一个'buildRobot'方法并且你定义了一个也实现了接口的子类,那么Java会发生什么? – toto2

+0

@toto显然,只要返回类型相同就可以,请参阅此[线程](http://stackoverflow.com/questions/2801878/implemeting-2-interfaces-in-a-class-with-same-方法 - 这界面法-是-OV)。 – toto2

回答

20

编译器会将这种情况(即试图调用(some instance of RoboticsEngineer).buildRobot())标记为错误。

这是因为派生类对象已经得到了双方的基本对象的副本(A MechanicalEngineer实例和ElectricalEngineer实例)的自身内部和单独的方法签名是不够的,告诉使用哪一个。

如果您在RoboticsEngineer覆盖buildRobot,你就可以明确地说,其继承的方法通过在前面的类名来使用,例如:

void RoboticsEngineer::buildRobot() { 
    ElectricalEngineer::buildRobot() 
} 

通过同一枚硬币,你实际上可以“力”在这种情况下

(some instance of RoboticsEngineer).ElectricalEngineer::buildRobot(); 

ElectricalEngineer实施方法将被调用,不会产生歧义:编译器通过与类名前缀它使用一个版本或其他的buildRobot

当你有一个Engineer基类都MechanicalEngineerElectricalEngineer和您指定的继承是在这两种情况下virtual一种特殊情况给出。当使用virtual时,派生对象不包含Engineer的两个实例,但编译器确保只有一个实例。这应该是这样的:

class Engineer { 
     void buildRobot(); 
}; 

class MechanicalEngineer: public virtual Engineer { 

}; 

class ElectricalEngineer: public virtual Engineer { 

}; 

在这种情况下,

(some instance of RoboticsEngineer).buildRobot(); 

将可以解决,而模糊。如果buildRobot被声明为virtual并且在两个派生类之一中被重写,情况也是如此。无论如何,如果两个派生类(ElectricalEngineer和MechanicalEngineer)都会覆盖buildRobot,则会再次产生歧义,编译器会将调用(some instance of RoboticsEngineer).buildRobot();时的尝试标记为错误。

+0

可以说虚拟是相同的关键词“实施”在Java? –

+0

@Yochai Timmer:你能更精确吗?两者都应该是虚拟的?继承或方法?我所做的任何陈述都得到了一个编译器测试的支持...... @Kit Ho:我不太了解Java,但是因为虚拟继承对于多继承是有意义的,而且Java没有这个,所以我会怀疑它... – sergio

+0

@sergio:在你编辑你之前说过,你只需要使两个方法都是虚拟的。你现在有什么工作。虽然OP问如果两个基类都实现了这个方法会发生什么(问题不在于钻石继承) –

5

它不处理它。它含糊不清。 error C2385: ambiguous access of 'functionName'

编译器很聪明,知道它不应该猜出你的意思。
对于要编译的程序,您需要告诉编译器:
答:您知道这是一个有问题的问题。B,告诉它你究竟是什么意思。

要做到这一点,你需要明确地告诉你问哪个方法编译:

RoboticsEngineer myRobot; 
myRobot.ElectricalEngineer::buildRobot(); 
0

编译器会抱怨这种situtation的。

在这种情况下,C++建议使用“纯虚拟”方法buildRobot()函数创建接口。 MechanicalEngineer和EletricalEnginner将继承接口并覆盖buildRoboot()函数。

当您创建RoboticsEnginner对象并调用buildRobot()函数时,将调用该接口的函数。

+0

是否reli C++可以从两个以上的类继承? –

0
struct MecEngineer { 

    void buildRobot() { /* .... */ } 

}; 

struct EleEngineer { 

    void buildRobot() { /* .... */ } 

}; 

struct RoboticsEngineer : MecEngineer, EleEngineer { 

}; 

现在,当你这样做,

​​

这样的呼叫不能得到解决,是模糊的,因为无论是子对象具有相同的签名和编译器的成员函数不知道哪一个呼叫。在这种情况下,您需要使用::运营商或使用static_cast明确提及。

static_cast<MecEngineer*> (robEngObject) -> buildRobot() ; 
+0

演示:http://ideone.com/EgD7B – Mahesh

+0

实际上没有合乎逻辑的理由来使用范围操作符是足够的,更短的,并且通常在实践中更可接受。 –

0

没有关于多个类的继承允许这一点。 Java产生与接口相同的问题。

public interface A { 
    public void doStuff(); 
} 
public interface B { 
    public void doStuff(); 
} 
public class C implements A, B {} 

简单的答案是编译器会在其上引发错误。

+0

在这种情况下,编译器为什么会抛出错误/会抛出什么错误?记住Java中的接口就像纯虚函数一样。因此C需要实现这个函数,调用它将不会造成歧义。 – Pratham