这个函数调用真的很模糊吗?

时间:2016-12-31 23:32:10

标签: c++ inheritance polymorphism virtual

我正在学习多重继承和钻石问题,当我从最派生的类中调用函数时,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类中重写了基类函数,那么调用将是不明确的,但不是&#34; aFunction()&#34;在B和C中是一样的吗?

此外,使B和C从A继承实际上会使错误消失。但我对关键字&#34;虚拟&#34;的理解当继承,即(Derived:virtual Base)时,它会阻止一个更多的派生类&#34;从链上继承Base的多个副本进一步向下。在继承中,可以继承成员变量的多个副本,但只能复制具有相同名称的函数的一个副本。因此,例如,我可以有5个派生类,每个派生自Base,然后是从所有5个派生类继承的MostDerivedClass,在MostDerivedClass中,我将拥有5个Base类和#34;成员变量&#34;的副本,但仅限于一个具有相同名称的函数的副本。

换句话说,&#34;虚拟&#34;继承关键字应该防止多个Base&#34;成员变量&#34;副本。我不明白为什么在这种情况下它会清除一个模糊的函数调用。

编辑:谢谢你,它正在慢慢沉入。我无法想象&#34;两份副本&#34; D中的A,因为A是空的(没有大小)。但后来我记得C ++从不创建空类,在我的设置上,例如一个空类的大小为1.然后我能够想象&#34;两个副本&#34; D中的A,它现在开始有意义了。

3 个答案:

答案 0 :(得分:5)

调用不明确,因为有两个可能的private string ReturnTop(IEnumerable<string> current, IEnumerable<string> topList) { var topMap = topList.Select((value, index) => new {Value = value, Index = index}) .ToDictionary(item => item.Value, item => item.Index); string minItem = null; int minPosition = topMap.Count; foreach (var item in current) { var currentPosition = topMap[item]; if (currentPosition == 0) { return item; } if (currentPosition < minPosition) { minPosition = currentPosition; minItem = item; } } return minItem; } 基础对象可以作为调用的A参数传递。即使它是最终被调用的相同的物理函数,并且该函数完全忽略了它的this参数,但是它们中有两个使它变得模棱两可。

使用this继承意味着只有一个virtual基础对象,因此调用不会有歧义。

答案 1 :(得分: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?

编译器可以检测到没有引用它的内联函数的特定情况,但是您可以轻松地解决该问题,因此对于相对罕见的情况而言,它不值得复杂。

答案 2 :(得分:0)

使用虚拟继承来解决钻石问题:

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 {};