2016-12-31 60 views
4

我学习的多重继承和钻石的问题,当我做一个函数调用从最派生类的Visual Studio告诉我,电话是模糊的:这个函数调用真的很模糊吗?

struct A 
{ 
    virtual void aFunction() { cout << "I am A\n"; } 
}; 
struct B : A {}; 
struct C : A {}; 
struct D : B, C {}; 

int main() 
{ 
    D DObj; 
    DObj.aFunction();    // This is an ambiguous call 
} 

我明白,如果我已经覆盖了B和C类中的基类函数,那么调用将是不明确的,但是在B和C中不是“aFunction()”吗?

而且,使得B和C继承了一个几乎让错误消失。但是,当我们继承关键字“虚拟”时,我理解的是它(派生:虚拟基础),它阻止了一个“更多的派生类”沿着链的下游继承多个副本。在继承中,成员变量的多个副本可以被继承,但只有一个具有相同名称的函数副本。因此,例如,我可以在MostDerivedClass 5个派生类分别从基地派生,然后MostDerivedClass从所有5个派生类继承,我将有基地班“的成员变量”的5个人副本,但只有一个功能的副本同名。

因此,换句话说,对于继承“虚拟”关键字应该防止多个基地“成员变量”副本。我不明白为什么它会在这种情况下清除模糊的函数调用。

编辑:谢谢你,它在慢慢下沉这是不可能的,我想象中的d“一分式两份” A,因为A是空的(大小)。但后来我记得C++从不创建空类,例如在我的设置中,空类的大小为1.然后我可以想象D中的A的“两个副本”,现在开始有意义。

+0

我认为,如果没有虚拟,你有功能的2个相同的副本(虽然这仍然是我要学习自己) –

+4

是的,这是正确的。 D包含两个A实例。编译器不知道是否要调用D :: B :: A :: aFunction或D :: C :: A :: aFunction。尽管在任何情况下调用的函数都是相同的,但不同的调用会得到不同的this指针。如果你从A虚拟出来,那么你将只有一个A而且没有歧义。 'struct B:virtual A {};'和'struct C:virtual A {};'。 – Waxrat

+0

(为了证明这不是Visual C++编译器的问题),GCC 5.1给出了[同样的错误](http:// ideone。com/9QYJwy) – UnholySheep

回答

5

该调用是不明确的,因为有两个可能的A基础对象可以作为调用的this参数传递。尽管它是完全相同的物理函数,并且该函数完全忽略了它的参数,但它们中有两个使得它不明确。

使用virtual继承意味着将只有一个A基础对象,因此该调用不会含糊不清。

2

因为成员变量的多个副本继承,你可以有不同的行为函数的两个单独的副本。

struct A 
{ 
    int x; 
    virtual void aFunction() { cout << "I am A with value " << x ; } 
}; 
struct B : A { 
}; 
struct C : A { 
}; 
struct D : B, C {}; 

int main() 
{ 
    D DObj; 
    ((B*)(&DObj))->x = 0; // set the x in B to 0 
    ((C*)(&DObj))->x = 1; // set the x in C to 1 
    DObj.aFunction();    // This is an ambiguous call 
} 

应该输出0还是1?

编译器可以检测不引用这个内联函数的具体情况,但你可以很容易地解决这个问题,使它不值得为一个比较罕见的情况下的复杂性。

+0

在你的例子中,如果D最后调用了B的构造函数或A的构造函数,这无关紧要吗?这是令人困惑的,但是如果当D被构造时它调用B的构造函数,那么C的构造函数,那么答案应该是1.而如果它叫做另一种方式则为0? – Zebrafish

+0

关键是x成员变量有两个副本,所以函数应该引用哪个版本? – user1937198

+0

@TitoneMaurice如果你没有虚拟地继承A,那么A有两个副本,一个在B中,另一个在C中,所以你有两个x副本。当您通过D访问时,访问哪个版本的x是很困难的。 – user1937198

0

使用虚拟继承来解决菱形prolem:

struct A 
{ 
    int x; 
    virtual void aFunction() { cout << "I am A with value " << x ; } 
}; 
struct B : virtual A { // add virtual 
}; 
struct C : virtual A { // virtual 
}; 
struct D : B, C {};