多个超类中的多重继承,C ++和相同方法签名

时间:2022-06-02 22:39:29

I have no experience in C++, and I come from a Java background. Lately, I was asked in an interview on why Java would not allow multiple inheritence and the answer was pretty easy. However, I am still curious on how C++ deals with that since it allows you to inherit from more than one class.

我没有C ++经验,而且我来自Java背景。最近,我在接受采访时被问到为什么Java不允许多重继承,答案很简单。但是,我仍然很好奇C ++如何处理它,因为它允许你从多个类继承。

Specifically, say there is a class called MechanicalEngineer and another called ElectricalEngineer. Both have a method called buildRobot().

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

What happens if we make a third class RoboticsEngineer, that inherets from both and does not override that method, and you just call:

如果我们制作第三类RoboticsEngineer会发生什么情况,这种情况从两者中都有,并且不会覆盖该方法,您只需调用:

(some instance of RoboticsEngineer).buildRobot()

Will an exception be thrown, or the method from one of the super-classes will be used? If so, how does the compiler know which class to use?

是否会抛出异常,或者是否会使用其中一个超类的方法?如果是这样,编译器如何知道要使用哪个类?

5 个解决方案

#1


21  

The compiler will flag this kind of situation (i.e., attempting to call (some instance of RoboticsEngineer).buildRobot()) as an error.

编译器将标记这种情况(即,尝试调用(RoboticsEngineer的某个实例).buildRobot())作为错误。

This happens because the derived object has got a copy of both base objects (a MechanicalEngineer instance and an ElectricalEngineer instance) inside of itself and the method signature alone is not enough to tell which one to use.

发生这种情况是因为派生对象内部有两个基础对象(一个MechanicalEngineer实例和一个ElectricalEngineer实例)的副本,而单独的方法签名不足以告诉使用哪一个。

If you override buildRobot in your RoboticsEngineer, you will be able to say explicitly which inherited method to use by prefixing the class name, e.g.:

如果在RoboticsEngineer中覆盖buildRobot,则可以通过为类名添加前缀来明确说明要使用哪个继承方法,例如:

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

By the same coin, you can actually "force" the compiler to use one version or another of buildRobot by prefixing it with the class name:

通过相同的硬币,您实际上可以“强制”编译器使用buildRobot的一个版本或另一个版本,方法是在其前面添加类名:

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

in this case the ElectricalEngineer implementation of the method will be called, no ambiguity.

在这种情况下,将调用该方法的ElectricalEngineer实现,没有歧义。

A special case is given when you have an Engineer base class to both MechanicalEngineer and ElectricalEngineer and you specify the inheritance to be virtual in both cases. When virtual is used, the derived object does not contain two instances of Engineer, but the compiler makes sure that there is only one of it. This would look like this:

如果您有MechanicalEngineer和ElectricalEngineer的Engineer基类,并且在两种情况下都指定继承为虚拟,则会给出一个特例。使用虚拟时,派生对象不包含两个Engineer实例,但编译器确保只有一个实例。这看起来像这样:

 class Engineer {
      void buildRobot();
 };

 class MechanicalEngineer: public virtual Engineer {

 };

 class ElectricalEngineer: public virtual Engineer {

 };

In this case,

在这种情况下,

(some instance of RoboticsEngineer).buildRobot();

will be resolved without ambiguities. The same is true if buildRobot is declared virtual and overridden in one of the two derived classes. Anyway, if both derived classes (ElectricalEngineer and MechanicalEngineer) overrides buildRobot, then ambiguity arises once again and the compiler will flag the attempt at calling (some instance of RoboticsEngineer).buildRobot(); as an error.

将毫不含糊地解决。如果将buildRobot声明为虚拟并在两个派生类之一中重写,则同样如此。无论如何,如果两个派生类(ElectricalEngineer和MechanicalEngineer)都覆盖了buildRobot,那么歧义再次出现,编译器将标记调用的尝试(RoboticsEngineer的某个实例).buildRobot();作为一个错误。

#2


5  

It doesn't handle it. It's ambiguous. error C2385: ambiguous access of 'functionName'

它没有处理它。这是模棱两可的。错误C2385:'functionName'的模糊访问

The compiler is smart enough to know that it shouldn't guess your meaning.
For the program to compile, you need to tell the compiler that:
A. You know it's a problematic issue.
B. Tell it what exactly you mean.

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

To do this, you need to explicitly tell the compiler which method you're asking for:

为此,您需要明确告诉编译器您要求的方法:

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

#3


0  

The compiler will complain about this kind of situtation.

编译器会抱怨这种情况。

In such a case c++ suggest to create an Interface with a "pure virtual" method buildRobot() function. MechanicalEngineer and EletricalEnginner will inherit the Interface and override the buildRoboot() function.

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

When you create RoboticsEnginner object and call the buildRobot() function, the interface's function will be called.

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

#4


0  

struct MecEngineer {

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

};

struct EleEngineer {

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

};

struct RoboticsEngineer : MecEngineer, EleEngineer {

};

Now when you do,

现在当你这样做的时候

robEngObject -> buildRobot() ;

Such a call cannot be resolved and is ambiguous because both the sub-objects has a member function with same signature and compiler doesn't know which one to call. In such a situation, you need to explicitly mention it using :: operator or by using static_cast.

这样的调用无法解决且不明确,因为两个子对象都具有相同签名的成员函数,并且编译器不知道要调用哪个。在这种情况下,您需要使用:: operator或使用static_cast明确提及它。

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

#5


0  

There is nothing about multiple class inheritance that allows this. Java produces the same problem with interfaces.

没有任何关于允许这种情况的多类继承。 Java会产生相同的接口问题。

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

The simple answer is that the compiler throws an error on it.

简单的答案是编译器会抛出错误。

#1


21  

The compiler will flag this kind of situation (i.e., attempting to call (some instance of RoboticsEngineer).buildRobot()) as an error.

编译器将标记这种情况(即,尝试调用(RoboticsEngineer的某个实例).buildRobot())作为错误。

This happens because the derived object has got a copy of both base objects (a MechanicalEngineer instance and an ElectricalEngineer instance) inside of itself and the method signature alone is not enough to tell which one to use.

发生这种情况是因为派生对象内部有两个基础对象(一个MechanicalEngineer实例和一个ElectricalEngineer实例)的副本,而单独的方法签名不足以告诉使用哪一个。

If you override buildRobot in your RoboticsEngineer, you will be able to say explicitly which inherited method to use by prefixing the class name, e.g.:

如果在RoboticsEngineer中覆盖buildRobot,则可以通过为类名添加前缀来明确说明要使用哪个继承方法,例如:

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

By the same coin, you can actually "force" the compiler to use one version or another of buildRobot by prefixing it with the class name:

通过相同的硬币,您实际上可以“强制”编译器使用buildRobot的一个版本或另一个版本,方法是在其前面添加类名:

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

in this case the ElectricalEngineer implementation of the method will be called, no ambiguity.

在这种情况下,将调用该方法的ElectricalEngineer实现,没有歧义。

A special case is given when you have an Engineer base class to both MechanicalEngineer and ElectricalEngineer and you specify the inheritance to be virtual in both cases. When virtual is used, the derived object does not contain two instances of Engineer, but the compiler makes sure that there is only one of it. This would look like this:

如果您有MechanicalEngineer和ElectricalEngineer的Engineer基类,并且在两种情况下都指定继承为虚拟,则会给出一个特例。使用虚拟时,派生对象不包含两个Engineer实例,但编译器确保只有一个实例。这看起来像这样:

 class Engineer {
      void buildRobot();
 };

 class MechanicalEngineer: public virtual Engineer {

 };

 class ElectricalEngineer: public virtual Engineer {

 };

In this case,

在这种情况下,

(some instance of RoboticsEngineer).buildRobot();

will be resolved without ambiguities. The same is true if buildRobot is declared virtual and overridden in one of the two derived classes. Anyway, if both derived classes (ElectricalEngineer and MechanicalEngineer) overrides buildRobot, then ambiguity arises once again and the compiler will flag the attempt at calling (some instance of RoboticsEngineer).buildRobot(); as an error.

将毫不含糊地解决。如果将buildRobot声明为虚拟并在两个派生类之一中重写,则同样如此。无论如何,如果两个派生类(ElectricalEngineer和MechanicalEngineer)都覆盖了buildRobot,那么歧义再次出现,编译器将标记调用的尝试(RoboticsEngineer的某个实例).buildRobot();作为一个错误。

#2


5  

It doesn't handle it. It's ambiguous. error C2385: ambiguous access of 'functionName'

它没有处理它。这是模棱两可的。错误C2385:'functionName'的模糊访问

The compiler is smart enough to know that it shouldn't guess your meaning.
For the program to compile, you need to tell the compiler that:
A. You know it's a problematic issue.
B. Tell it what exactly you mean.

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

To do this, you need to explicitly tell the compiler which method you're asking for:

为此,您需要明确告诉编译器您要求的方法:

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

#3


0  

The compiler will complain about this kind of situtation.

编译器会抱怨这种情况。

In such a case c++ suggest to create an Interface with a "pure virtual" method buildRobot() function. MechanicalEngineer and EletricalEnginner will inherit the Interface and override the buildRoboot() function.

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

When you create RoboticsEnginner object and call the buildRobot() function, the interface's function will be called.

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

#4


0  

struct MecEngineer {

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

};

struct EleEngineer {

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

};

struct RoboticsEngineer : MecEngineer, EleEngineer {

};

Now when you do,

现在当你这样做的时候

robEngObject -> buildRobot() ;

Such a call cannot be resolved and is ambiguous because both the sub-objects has a member function with same signature and compiler doesn't know which one to call. In such a situation, you need to explicitly mention it using :: operator or by using static_cast.

这样的调用无法解决且不明确,因为两个子对象都具有相同签名的成员函数,并且编译器不知道要调用哪个。在这种情况下,您需要使用:: operator或使用static_cast明确提及它。

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

#5


0  

There is nothing about multiple class inheritance that allows this. Java produces the same problem with interfaces.

没有任何关于允许这种情况的多类继承。 Java会产生相同的接口问题。

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

The simple answer is that the compiler throws an error on it.

简单的答案是编译器会抛出错误。