Multiple instances of a virtual base class subobject (really)
Given the code:
#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;
}
can we make the second assert fail?
In other words, this is the case when we have a two-diamond inheritance graph and would like to have separate subobjects for both diamonds' tops in the most derived object.
The standard (2003, 10.1.4) wording seems to prohibit this, and if really so, the follow-up question is: are we given no means of precise virtual-over-multiply-included subobject structure manipulation, and why?
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.
As a basic rule, all virtual base classes of the same type are merged (non-virtual base classes are not merged with the virtual one, though). There's no mechanism to block a virtual base class from being shared. The reason probably is that any such mechanism would have needed quite some effort to design (and also effort for compiler writers to implement) for very little gain (did you ever get into the situation where you actually wished for that functionality?)
You can achieve some sort of comparison via double dispatch. It's not perfect. This can be done with less code too, but I just wanted to show the idea behind it.
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/78938.html
上一篇: 继承构造函数和虚拟基类
下一篇: 虚拟基类子对象的多个实例(真的)