虚拟基类子对象的多个实例(真的)

给定代码:

#include <cassert>


struct X {};

struct Y1: virtual X {};
struct Y2: virtual X {};
struct Y3: virtual X {};
struct Y4: virtual X {};

struct Z1: Y1, Y2 {};
struct Z2: Y3, Y4 {};

struct XYZ: Z1, Z2 {};


int main() {
    XYZ xyz;

    X *x1 = static_cast<Y1*>(&xyz);
    X *x2 = static_cast<Y2*>(&xyz);
    X *x3 = static_cast<Y3*>(&xyz);
    X *x4 = static_cast<Y4*>(&xyz); 

    assert( x1 == x2 ); //first pair, ok
    assert( x2 == x3 ); //can we make this one fail?
    assert( x3 == x4 ); //second pair, ok


    return 0;
}

我们可以让第二个断言失败吗?

换句话说,当我们有一个双钻石继承图并且希望在最衍生的对象中有两个钻石顶部都有单独的子对象时,就是这种情况。

标准(2003,10.1.4)的措辞似乎禁止了这一点,如果确实如此,后续的问题是:我们是否没有被精确的虚拟多次包含子对象结构操纵的手段,为什么?


一旦基地被宣布为虚拟的,那个虚拟基地的所有来源都被折叠成该类型的一个基地,它不会让你在分级结构的一半之间分裂它(没有任何东西可以让孩子去解除父母的虚假)。 要明确的是,从非虚拟继承基础的不同类继承将导致另一个实例。 您可以使用XYZ组合来创建两个实例而不是继承,然后使用正常的接口进行适当的委托。


作为基本规则,合并所有相同类型的虚拟基类(非虚拟基类不与虚拟基类合并)。 没有机制阻止共享虚拟基类。 原因可能是任何这样的机制都需要付出相当大的努力来设计(并且也是编译器编写者努力实现的),而获得很少的收益(您是否曾经陷入过实际上希望获得该功能的情况?)


你可以通过双重派遣实现某种比较。 这并不完美。 这可以用更少的代码完成,但我只是想展示它背后的想法。

class BaseX {
    bool Equals(BaseX* potentialBaseX) {
        if(potentialBaseX) {
            return potentialBaseX->TestEquals(this);
        }
        // handles null
        return false;
    }

    // OK: x to x
    virtual bool TestEquals(BaseX* baseX) { return true; }
    virtual bool TestEquals(DerivedY1* derivedY) { return false; }
    virtual bool TestEquals(DerivedY2* derivedY) { return false; }
    virtual bool TestEquals(DerivedY3* derivedY) { return false; }
    virtual bool TestEquals(DerivedY4* derivedY) { return false; }
};
class DerivedY1 {
    // OK: y1 to y1, y1 to y2
    virtual bool TestEquals(BaseX* baseX) { return false; }
    virtual bool TestEquals(DerivedY1* derivedY) { return true; }
    virtual bool TestEquals(DerivedY2* derivedY) { return true; }
    virtual bool TestEquals(DerivedY3* derivedY) { return false; }
    virtual bool TestEquals(DerivedY4* derivedY) { return false; }
};    
class DerivedY2 {
    // OK: y2 to y2, y2 to y1
    virtual bool TestEquals(BaseX* baseX) { return false; }
    virtual bool TestEquals(DerivedY1* derivedY) { return true; }
    virtual bool TestEquals(DerivedY2* derivedY) { return true; }
    virtual bool TestEquals(DerivedY3* derivedY) { return false; }
    virtual bool TestEquals(DerivedY4* derivedY) { return false; }
};
class DerivedY3 {
    // OK: y3 to y3, y3 to y4
    virtual bool TestEquals(BaseX* baseX) { return false; }
    virtual bool TestEquals(DerivedY1* derivedY) { return false; }
    virtual bool TestEquals(DerivedY2* derivedY) { return false; }
    virtual bool TestEquals(DerivedY3* derivedY) { return true; }
    virtual bool TestEquals(DerivedY4* derivedY) { return true; }
};
class DerivedY4 {
    // OK: y4 to y4, y4 to y3
    virtual bool TestEquals(BaseX* baseX) { return false; }
    virtual bool TestEquals(DerivedY1* derivedY) { return false; }
    virtual bool TestEquals(DerivedY2* derivedY) { return false; }
    virtual bool TestEquals(DerivedY3* derivedY) { return true; }
    virtual bool TestEquals(DerivedY4* derivedY) { return true; }
};

//Using your example:
assert( x1.Equals(x2) ); //first pair, ok
assert( x2.Equals(x3) ); //can we make this one fail?
assert( x3.Equals(x4) ); //second pair, ok
链接地址: http://www.djcxy.com/p/78937.html

上一篇: Multiple instances of a virtual base class subobject (really)

下一篇: In C++, what is a virtual base class?