具有混合虚拟和非虚拟基础的C ++ 11类格?

时间:2013-06-02 20:03:47

标签: c++ c++11

在C ++ 11(N3485)10.1.4 [class.mi]中它说:

  

对于最派生类的类网格中非虚拟基类的每个不同出现,最派生的对象应包含对应的 distinct 基类子对象那种类型。

     

对于指定为 virtual 的每个不同基类,派生程度最高的类应包含该类型的单个基类对象。

考虑以下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)那么标准中的语言不正确,因为类格子中只能出现一个类?

1 个答案:

答案 0 :(得分: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)就不足以说“每次出现一个   类格中的基类有一个对应的基类   子对象“?”也就是说,如果已经构造了格子   取决于要选择的虚拟和非虚基类关系   边和顶点?

合并你的建议......

  

包含关键字虚拟的基类说明符,   指定虚拟基类。对于每个 distinct   在类点阵中出现非虚拟基类   最派生类的,派生最多的对象(1.8)应该   包含,有一个对应的 distinct   该类型的基类子对象 对于每个不同的   指定虚拟的基类,派生的对象最多   包含该类型的单个基类子对象。

我不是标准语言一半的专家。但是,当我阅读您修改后的规范时,我看不出如何:

class V { /∗...∗/ };
class A : virtual public V { /∗ ... ∗/ };
class B : virtual public V { /∗ ... ∗/ };
class C : public A, public B { /∗...∗/ };

图4中的结果:

   V
  / \
 /   \
A     B
 \   /
  \ /
   C

我没有在标准中看到另一个地方指定尽管VC下面的类层次结构中出现两次,但实际上只存在一个V类型的子对象,因为使用virtual关键字。