为了完全理解如何解决Java的多重继承问题,我有一个经典的问题需要澄清.
可以说我有类Animal此有子类Bird和Horse我需要做一个类Pegasus,从扩展Bird和Horse自Pegasus既是一只鸟和一匹马.
我认为这是经典的钻石问题.从我能理解经典的方式来解决,这是使Animal,Bird和Horse类接口,并实现Pegasus从他们.
我想知道是否有另一种方法来解决我仍然可以为鸟类和马创造物体的问题.如果有一种方法可以创造动物,那将是伟大的但不是必要的.
java oop multiple-inheritance diamond-problem multiple-interface-implem
class A { public: void eat(){ cout<<"A";} };
class B: virtual public A { public: void eat(){ cout<<"B";} };
class C: virtual public A { public: void eat(){ cout<<"C";} };
class D: public B,C { public: void eat(){ cout<<"D";} };
int main(){
A *a = new D();
a->eat();
}
Run Code Online (Sandbox Code Playgroud)
我理解钻石问题,上面的代码没有那个问题.
虚拟继承究竟是如何解决问题的?
我的理解:
当我说A *a = new D();,编译器想要知道类型的对象是否D可以分配给类型的指针A,但它有两个可以遵循的路径,但不能自己决定.
那么,虚拟继承如何解决问题(帮助编译器做出决定)?
c++ inheritance multiple-inheritance virtual-inheritance diamond-problem
请考虑以下代码:
struct A
{
void f()
{
}
};
struct B1 : A
{
};
struct B2 : A
{
};
struct C : B1, B2
{
void f() // works
{
B1::f();
}
//using B1::f; // does not work
//using B1::A::f; // does not work as well
};
int main()
{
C c;
c.f();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我恳请你不要复制粘贴标准答案如何解决钻石问题("使用虚拟继承").我在这里问的是为什么在这种情况下使用声明不起作用.确切的编译器错误是:
In function 'int main()':
prog.cpp:31:6: error: 'A' is an ambiguous base of 'C'
c.f();
Run Code Online (Sandbox Code Playgroud)
我得到的印象是使用声明应该从这个例子开始:
struct A
{
void f()
{ …Run Code Online (Sandbox Code Playgroud) 考虑下面的python代码片段
class A(object):
def __init__(self, a):
self.a = a
class B(A):
def __init__(self, a, b):
super(B, self).__init__(a)
self.b = b
class C(A):
def __init__(self, a, c):
super(C, self).__init__(a)
self.c = c
class D(B, C):
def __init__(self, a, b, c, d):
#super(D,self).__init__(a, b, c) ???
self.d = d
Run Code Online (Sandbox Code Playgroud)
我想知道如何传递a,b以及c相应的基类的构造函数.
谢谢,
我正在尝试实现一个实现许多接口的相当大的对象.其中一些接口是纯虚拟的.我可能在钻石继承方面遇到问题.Visual Studio正在报告警告C4250 ('class1' : inherits 'class2::member' via dominance).首先,这些类实际上是应该继承的.以下是导致此问题的部分类设计.
A B C
\ / \ /
\ / \ /
AB BC
| |
| BC2
| |
\ D: Implementation of B, C, BC, BC2
\ /
Big
Run Code Online (Sandbox Code Playgroud)
在整个树中,只有D实现了虚方法,没有其他相关方法的定义.B的所有虚拟方法都列在警告中.如果重要,D是一个完整的类.
我读到这种情况发生在Boost序列化中,忽略警告是安全的.
这种方法我试图实现有效吗?忽视这个警告是否安全?
注1:这不是Visual Studio Compiler警告C4250('class1':通过优势继承'class2 :: member')的重复,我尝试了那里提出的解决方案.
注2:我也可以发送类图,但它比这复杂一点.
编辑: 完整警告如下:
warning C4250: 'gge::resource::ImageResource' : inherits
'gge::graphics::ImageTexture::gge::graphics::ImageTexture::drawin'
via dominance
Run Code Online (Sandbox Code Playgroud)
gge::resource::ImageResource在绘图中是大的,gge::graphics::ImageTexture是D,drawin是我得到警告的六种方法之一.
我在C ++中使用多重继承,并通过显式调用基本方法来扩展基本方法。假定以下层次结构:
Creature
/ \
Swimmer Flier
\ /
Duck
Run Code Online (Sandbox Code Playgroud)
对应于
Creature
/ \
Swimmer Flier
\ /
Duck
Run Code Online (Sandbox Code Playgroud)
现在,这带来了一个问题-调用duck的print方法将调用其各自的基本方法,所有这些方法都依次调用该Creature::print()方法,因此最终被两次调用-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
Run Code Online (Sandbox Code Playgroud)
我想找到一种方法来确保基本方法仅被调用一次。与虚拟继承的工作方式类似(在第一次调用时调用基本构造函数,然后仅在来自其他派生类的后续调用中为其分配一个指针)。
是否有一些内置方法可以做到这一点,还是我们需要依靠自己实现?
如果是这样,您将如何处理?
这个问题并非特定于打印。我想知道是否有一种机制可以扩展基本方法和功能,同时保持调用顺序并避免出现钻石问题。
我现在知道,最突出的解决方案是添加辅助方法,但是我只是想知道是否存在“更清洁”的方法。
关于钻石问题的维基百科:
"......当两个B和C类继承自A,而D类继承自B和C时,钻石问题就会产生歧义.如果D中的方法调用A中定义的方法(并且不重写方法) ),B和C以不同的方式覆盖了该方法,然后从哪个类继承:B或C?"
所以钻石看起来像这样:
A
/ \
B C
\ /
D
Run Code Online (Sandbox Code Playgroud)
我的问题是,如果没有这样的A类会发生什么,但B和C再次声明相同的方法,比如说foo().这不是同一个问题吗?为什么它被称为钻石问题?
例:
class B {
public void foo() {...}
}
class C {
public void foo() {...}
}
class D extends B, C {
}
new D().foo();
Run Code Online (Sandbox Code Playgroud) 对于Java人来说,这个问题可能听起来很奇怪,但如果你试图解释这个问题,那就太好了.
在这些日子里,我正在清除Java的一些非常基本的概念.所以我来谈谈Java的继承和接口主题.
在阅读本文时,我发现Java不支持多重继承,并且也明白,我无法理解为什么到处都会出现Diamond图形问题(至少有4个类来创建钻石)来解释这种行为,我们不能仅使用3个类来理解此问题.
说,我有A类和B类,这两个类是不同的(它们不是普通类的子类)但是它们有一个共同的方法,它们看起来像:
class A {
void add(int a, int b) {
}
}
class B {
void add(int a, int b) {
}
}
Run Code Online (Sandbox Code Playgroud)
好的,现在说Java是否支持多重继承,如果有一个类是A和B的子类,如下所示: -
class C extends A,B{ //If this was possible
@Override
void add(int a, int b) {
// TODO Auto-generated method stub
super.add(a, b); //Which version of this, from A or B ?
}
}
Run Code Online (Sandbox Code Playgroud)
然后编译器将无法找到从A或B调用哪个方法,这就是Java不支持多重继承的原因.那么这个概念有什么问题吗?
当我读到这个主题时,我能够理解钻石问题,但是我无法理解为什么人们没有给出三个类的例子(如果这是有效的一个,因为我们只使用了3个类来演示问题所以它很容易通过将其与钻石问题进行比较来理解.)
让我知道这个例子是否不适合解释问题,或者这也可以参考理解问题.
编辑: 我在这里得到一个近距离投票,说明问题不明确.这是一个主要问题: -
我能理解为什么"Java不支持多重继承"只有3个类,如上所述,或者我必须要有4个类(Diamond结构)来理解这个问题.
我们都知道有关多重遗传的钻石问题 -
A
/ \
B C
\ /
D
Run Code Online (Sandbox Code Playgroud)
这个问题描述了课堂的模糊情况D.如果类A有一个方法,并且/ B和/或C覆盖方法,那么哪个版本的方法会D覆盖?
这个问题是否也适用于Java中的接口?如果没有,Java接口如何克服这个问题?
diamond-problem ×10
c++ ×4
inheritance ×4
java ×4
oop ×3
interface ×2
java-8 ×1
python ×1
subclass ×1
super ×1