具有混合虚拟和非混合的C ++ 11类格
在C ++ 11(N3485)10.1.4 [class.mi]中说:
对于大多数派生类的类网格中的非虚拟基类的每个不同的发生,最多派生的对象将包含该类型的相应的不同基类子对象。
对于每个指定为虚拟的不同基类,最派生类应包含该类型的单个基类对象。
考虑下面的C ++ 11代码:
struct B {};
struct BV : virtual B {};
struct BN : B {};
struct C1 : BV, BN {};
struct C2 : BV, BN {};
struct D : C1, C2 {};
首先,为了清楚起见,D的类网格有多少个顶点?
其次,B类有多少个不同的子对象,这个标准要求类型D的派生对象最多?
更新:
以下哪一个是类格?
(1)
B B B B
^ ^ ^ ^
| | | |
BV BN BV BN
^ ^ ^ ^
| | | |
/ /
C1 C2
/
/
- D -
(2)
B<---------
^
| |
| B | B
| ^ | ^
| | | |
BV BN BV BN
^ ^ ^ ^
| | | |
/ /
C1 C2
/
/
- D -
(3)
B
/
/
BV BN
| / |
| / |
| / |
| / |
C1 C2
/
/
D
如果意图是(1)那么是不是不可能有任何不是树的DAG? (即钻石是不可能的)如果将它称作类树不是更好吗?
如果它是(2)不足以说“对于类网格中每个基类的出现都有一个对应的基类子对象”? 也就是说,如果格的构造已经依赖于虚拟和非虚拟基类关系来选择边和顶点?
如果它是(3)那么标准中的语言是不是不正确的,因为在类格中只能有一个类的出现?
以下哪一个是类格?
2
示范:
#include <iostream>
struct B {};
struct BV : virtual B {};
struct BN : B {};
struct C1 : BV, BN {};
struct C2 : BV, BN {};
struct D : C1, C2 {};
int
main()
{
D d;
C1* c1 = static_cast<C1*>(&d);
BV* bv1 = static_cast<BV*>(c1);
BN* bn1 = static_cast<BN*>(c1);
B* b1 = static_cast<B*>(bv1);
B* b2 = static_cast<B*>(bn1);
C2* c2 = static_cast<C2*>(&d);
BV* bv2 = static_cast<BV*>(c2);
BN* bn2 = static_cast<BN*>(c2);
B* b3 = static_cast<B*>(bv2);
B* b4 = static_cast<B*>(bn2);
std::cout << "d = " << &d << 'n';
std::cout << "c1 = " << c1 << 'n';
std::cout << "c2 = " << c2 << 'n';
std::cout << "bv1 = " << bv1 << 'n';
std::cout << "bv2 = " << bv2 << 'n';
std::cout << "bn1 = " << bn1 << 'n';
std::cout << "bn2 = " << bn2 << 'n';
std::cout << "b1 = " << b1 << 'n';
std::cout << "b2 = " << b2 << 'n';
std::cout << "b3 = " << b3 << 'n';
std::cout << "b4 = " << b4 << 'n';
}
我的输出:
d = 0x7fff5ca18998
c1 = 0x7fff5ca18998
c2 = 0x7fff5ca189a0
bv1 = 0x7fff5ca18998
bv2 = 0x7fff5ca189a0
bn1 = 0x7fff5ca18998
bn2 = 0x7fff5ca189a0
b1 = 0x7fff5ca189a8
b2 = 0x7fff5ca18998
b3 = 0x7fff5ca189a8
b4 = 0x7fff5ca189a0
如果它是(2)不足以说“对于类网格中每个基类的出现都有一个对应的基类子对象”? 也就是说,如果格的构造已经依赖于虚拟和非虚拟基类关系来选择边和顶点?
合并您的建议...
包含关键字virtual的基类说明符指定一个虚拟基类。 对于大多数派生类的类网格中的非虚拟基类的每个不同的情况,最大派生对象(1.8)应包含该类型的相应的不同基类子对象。 对于指定为虚拟的每个不同的基类,最多派生的对象应包含该类型的单个基类子对象。
我不是标准语言一半的专家。 但是,当我阅读您的修改后的规范时,我不知道如何:
class V { /∗...∗/ };
class A : virtual public V { /∗ ... ∗/ };
class B : virtual public V { /∗ ... ∗/ };
class C : public A, public B { /∗...∗/ };
图4中的结果:
V
/
/
A B
/
/
C
我没有看到标准中的另一个地方,它指定尽管V
在C
的类层次结构中出现两次,但由于使用了virtual
关键字,因此实际上只有一个V
类型的子对象存在。