1

给定代码:

#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) 的措辞似乎禁止这样做,如果确实如此,那么后续问题是:我们是否没有提供精确的虚拟多乘包含子对象结构操作的方法,为什么?

4

4 回答 4

1

最接近的东西(不漂亮):

struct XYZ1;
struct XYZ2;

struct XYZ1 : Z1 {
    XYZ2 &self;
    XYZ1 (XYZ2 &self) : self(self) {}
};
struct XYZ2 : Z2 {
    XYZ1 &self;
    XYZ2 (XYZ1 &self) : self(self) {}
};
struct XYZ {
    XYZ1 m1;
    XYZ2 m2;
    XYZ() : m1(m2), m2(m1) {}
};
于 2012-08-03T06:38:12.483 回答
1

Once a base is declared virtual, all sources of that virtual base are collapsed into one base of that type, it won't let you split it off halfway up the hierarchy (there's nothing you can say at a child to de-virtual a parent). Just to be clear, inheriting from a different class that non-virtually inherited the base would result in another instance. You could use composition in XYZ to create the two instances instead of inheritance, and then use a normal interface to delegate as appropriate.

于 2012-01-24T20:51:55.167 回答
1

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

于 2012-01-24T21:39:38.237 回答
1

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

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
于 2012-01-24T21:55:22.360 回答