Inheritance 为什么接口的多重继承比一组类的多重继承要容易得多?

Inheritance 为什么接口的多重继承比一组类的多重继承要容易得多?,inheritance,interface,Inheritance,Interface,为什么接口的多重继承比一组类的多重继承要容易得多? 我被困在一个大学问题上。 谢谢也许是因为粒度:您可以选择类应该实现哪些接口。而如果扩展一个类,则会自动继承整个类层次结构 如果您从不同的类继承了两个具有相同签名的方法,则调用此方法时会产生歧义。这是可以解决的,但可以说是一个混乱的局面 如果您使用相同的方法签名实现了两个接口,这并不重要,因为在调用该方法时,仍然只有一个实现可供选择 是上述问题的延伸,这使得情况更加混乱。当将多重继承限制到接口时,这个问题基本上消失了。两个可能的原因: 1.)钻石

为什么接口的多重继承比一组类的多重继承要容易得多? 我被困在一个大学问题上。
谢谢

也许是因为粒度:您可以选择类应该实现哪些接口。而如果扩展一个类,则会自动继承整个类层次结构

如果您从不同的类继承了两个具有相同签名的方法,则调用此方法时会产生歧义。这是可以解决的,但可以说是一个混乱的局面

如果您使用相同的方法签名实现了两个接口,这并不重要,因为在调用该方法时,仍然只有一个实现可供选择

是上述问题的延伸,这使得情况更加混乱。当将多重继承限制到接口时,这个问题基本上消失了。

两个可能的原因: 1.)钻石问题(在维基百科上查找), 2.)对象标识

class A { }
class B { }
class C : A, B { }

C * c = new C ();
A * a = c;
B * b = c;
然后,您不能通过简单地测试a==b来验证对象标识。如果您试图在一种语言中实现这一特性,就不能在后台使用简单的指针算法,因此每次访问一个类(独立于多重继承)的代价都要高得多,因为a和b不再是普通的指针

如果A和B是接口,您就知道问题所在(您知道它们将被继承),这样您就可以区别对待对接口的访问和对类的访问

顺便说一句:多类继承并不难实现

编辑:添加。它还引入了概念问题:

class C0 { virtual int meth { return 0; } };
class C1 : C0 { virtual int meth { return 1; } };
class C2 : C1, C0 { }
如果我们定义

C2 * c2 = new C2;
该怎么办

((C1 *) c2)->meth()


回来是为了不让人迷惑?(编辑:更正此示例。)

至少在.net中指出,接口方法仅适用于声明为接口类型或被约束为接口类型的对象。因此,如果一个
C1
具有方法
Foo
,并且还实现了接口
Intf1
Intf2
,每个接口都声明了一个方法
Foo
,那么在大多数情况下,存在三个名为
Foo
的方法这一事实并不重要,因为它们存在于本质上是独立的域中

此外,如果包含成员
Foo
的接口
IDerived1
IDerived2
继承
IBase
,则实现两个接口的类或继承两个接口的接口将只定义
IBase.Foo
的一个定义。
IDerived1
IDerived2
和/或两者派生的接口可以声明自己的
Foo
成员,但任何此类定义都将与
IBase.Foo
完全分离。将派生接口强制转换为
IBase
并在其上调用
Foo
将始终生成相同的
IBase.Foo
方法,无论是直接转换为
IBase
,还是先转换为其他接口。相反,如果一个类派生自另外两个类,而这两个类都重写了公共基类的同一个成员,那么如果一个类将派生类的对象强制转换到基类,然后尝试使用该成员,则不清楚会发生什么


顺便说一句,有两种情况会出现歧义。如果一个接口继承了两个具有相同名称的成员的接口,则可能需要使用一些技巧来迫使编译器偏向其中一个,或者让派生接口添加其自己的同名成员,这将使两个原始接口都受到影响。此外,在使用泛型时,可以约束泛型类型以实现多个接口,也可以从类继承。完成此操作后,如果接口和/或类共享成员名称,则可能会出现歧义。

谁更容易?语言设计师?编译器编写者?使用该语言的程序员?多类继承不仅更加困难,而且对于java程序员来说是不可能的。对不起,忽略我的“java”标记。我指的是一般的语言。谢谢,但在实现接口时,您会自动获得整个接口层次结构。是的,但它们只是签名:PYup。但你的回答有误导性。关于你的后一个问题,我看不出有任何含糊不清之处;第一个调用应返回1,后一个调用应返回0。如果两个类
C1a
C1b
继承一个公共基类
C0
,并覆盖同一个虚拟成员
f
,而另一个类
C2
从这两个类继承,则会出现问题。如果必须在某一时间执行一个级别的向上广播(例如给定
C2 it
,则不能只说
(C0)it
,而必须说
(C0)(C1a)it
(C0)(C1b)it
)来解决歧义,但
(C0)(C1a)it
(C0)(C1b)it
的行为与不同类型的对象相似,或者作为不同的对象。对不起,我的示例设置得很草率(没有指针)。然而,我确实看到了概念上的问题,因为您可以为
(C0*)c2->meth()
返回0而争论(由于
C2
直接继承自
C0
C2
没有定义
meth
,并且不清楚为什么
类C2:C1,C0
在转换为
C0
时应该与
类C2:C0
不同,或者你可以为1(因为
(C0*)(C1*))c2
不应与
(C0*)c2
)有所不同。如果一种语言自由地支持多重继承,我看不到任何方法来保持身份,即
(TFinalType)(TIntermediate1)thing
在所有情况下都等同于
(TFinalType)(TIntermediate2)thing
((C0 *) c2)->meth()