代码之家  ›  专栏  ›  技术社区  ›  dyp

调用虚拟基类的重载构造函数

  •  11
  • dyp  · 技术社区  · 14 年前

    有没有一种(实用的)方法来旁路普通(虚拟)构造函数调用顺序?

    例子:

    class A
    {
        const int i;
    
    public:
        A()
          : i(0)
        { cout << "calling A()" << endl; }
    
        A(int p)
          : i(p)
        { cout << "calling A(int)" << endl; }
    };
    
    class B
        : public virtual A
    {
    public:
        B(int i)
          : A(i)
        { cout << "calling B(int)" << endl; }
    };
    
    class C
        : public B
    {
    public:
        C(int i)
          : A(i), B(i)
        { cout << "calling C(int)" << endl; }
    };
    
    class D
        : public C
    {
    public:
        D(int i)
          : /*A(i), */ C(i)
        { cout << "calling D(int)" << endl; }
    };
    
    
    int main()
    {
        D d(42);
        return 0;
    }
    

    输出:

    调用()
    调用B(int)
    调用C(int)
    调用d(int)

    我想要的是:

    调用(int)
    调用B(int)
    调用C(int)
    调用d(int)


    如您所见,涉及到虚拟继承,这导致d的构造函数调用第一个的构造函数,但由于没有提供参数,所以它调用()。这里有 康斯特 我需要初始化,所以我有个问题。

    我想做的是隐藏C的继承细节,这就是为什么我要寻找一种避免在D(和每个派生)构造函数的初始化列表中调用(i)的方法。[编辑]在这种特定的情况下,我可以假设只有C的非虚拟单继承子类(因为D是C的子类)。[/编辑]

    [编辑]

    虚拟基类是在初始化任何非虚拟基类之前初始化的,因此只有最派生的类才能初始化虚拟基类。杰姆斯·麦克内利

    这就是重点,我 不要 希望最派生的类调用虚拟基类构造函数。 [/编辑]

    考虑以下情况( 上面的代码示例中没有表示 ):

      A
     / \
    B0  B1
     \ /
      C
      |
      D  
    

    我理解为什么C在实例化C时必须调用(歧义)的ctor,但是为什么D在实例化D时必须调用它?

    4 回复  |  直到 7 年前
        1
  •  7
  •   Smi    11 年前

    不幸的是,您总是必须从最派生的类调用虚拟基类构造函数。

    这是因为您要说的是,虚拟基在为对象实例派生的所有类之间共享。由于一个构造函数只能在一个对象的给定实例化中调用一次,所以必须显式调用最派生类中的构造函数,因为编译器不知道有多少类共享虚拟基础(从C++编程语言第三版,第152.4.1节)释义(可能很差)。这是因为编译器将从最基本类的构造函数开始,并工作到最派生的类。按照标准,直接从虚拟基类继承的类不会调用其虚拟基类构造函数,因此必须显式调用它。

        2
  •  2
  •   Troubadour    14 年前

    我明白为什么C要打电话给 当你 说明c,但为什么d必须 通知时叫它?

    因为同样的原因,C不得不称之为它。这不是一个模棱两可的问题,而是一个事实,即a的constructIOR必须只被调用一次(因为它是一个虚拟基)。

    如果您希望C可以初始化A的构造函数,那么如果类D继承C和另一个最终继承A的类呢?

        3
  •  0
  •   curiousguy    7 年前

    规则就是这样。有重写虚拟函数的规则和构建虚拟基子对象的规则。尽管两者在概念上非常相似,但它们遵循完全不同的规则,原因之一是:重写虚函数是显式的。调用构造函数对于默认构造函数是隐式的。

    虚拟基类中的虚拟函数只需要有一个最终重写器,即重写所有其他重写器的重写器。(非虚拟基类中的虚拟函数不能有两个重写器,这样一个重写器就不会重写另一个。)

    但是,虚拟基类构造函数总是从最派生的类调用,并且通常以隐式形式(不必在ctor init列表中提及虚拟基类),因为大多数设计用作虚拟基类的类都是“纯接口”,没有数据成员,也没有用户初始化。

        4
  •  -1
  •   Shamster    14 年前

    关于PARASIFIFT C++FAQ Lite这个问题 is outlined .