调用虚拟基类的重载构造函数 [英] Calling a virtual base class's overloaded constructor

查看:165
本文介绍了调用虚拟基类的重载构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一种(实际)方法来绕过正常(虚拟)构造函数调用顺序?



示例: >

  class A 
{
const int i;

public:
A()
:i(0)
{cout< 调用A()< endl }

A(int p)
:i(p)
{cout< 调用A(int)< endl }
};

class B
:public virtual A
{
public:
B(int i)
:A(i)
{cout< 调用B(int)< endl }
};

class C
:public B
{
public:
C(int i)
:A(i),B )
{cout<< 调用C(int)< endl }
};

class D
:public C
{
public:
D(int i)
:/ * A(i) / C(i)
{cout< 调用D(int)< endl }
};


int main()
{
D d(42);
return 0;
}

输出


调用A()

调用B(int)

调用C(int)

调用D(int)


我想要的是:



< blockquote>

调用A(int)

调用B(int)

调用C(int)

调用D







如您所见,涉及虚拟继承,先调用A的构造函数,但由于没有提供参数,它调用A()。有 const int i需要初始化,所以我有一个问题。



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


>虚拟基类在初始化任何非虚拟基类之前进行初始化,因此只有最多的派生类可以初始化虚拟基类。 - James McNellis


这正是要点,我不要要最多派生类调用虚拟基类构造函数。



请考虑以下情况(未在上述代码示例中显示) :

  A 
/ \
B0 B1
\ /
C
|
D



我理解为什么C必须调用A的转义实例化C,但为什么D实例化D时必须调用它?

解决方案

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



这是因为你说的是​​虚拟基础是从对象的实例派生的所有类之间共享的。因为对于给定的对象实例,构造函数只能被调用一次,所以你必须显式地调用大多数派生类中的构造函数,因为编译器不知道有多少类共享虚拟基础(可能很差) C ++ Programming Language 3rd edition,section 15.2.4.1)。这是因为编译器将从最基础的类的构造函数开始,并且工作到最导出的类。直接从虚拟基类继承的类,不会被标准调用其虚拟基类构造函数,因此必须显式调用。


Is there a (practical) way to by-pass the normal (virtual) constructor calling order?

Example:

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;
}

Output:

calling A()
calling B(int)
calling C(int)
calling D(int)

What I want to have is something like:

calling A(int)
calling B(int)
calling C(int)
calling D(int)


As you see, there is virtual inheritance involved, which leads the constructor of D to call the constructor of A first, but since no parameter is provided, it calls A(). There's the const int i that needs initialisation, so I've got a problem.

What I'd like to do is to hide the inheritance details of C, that's why I'm looking for a way to avoid calling A(i) in D's (and every derived) constructor's initialisation list. [edit] In this specific case, I can assume there are only non-virtual single-inheritance child classes of C (as D is one). [/edit]

[edit]

Virtual base classes are initialized before any non-virtual base classes are initialized, so only the most derived class can initialize virtual base classes. – James McNellis

That's exactly the point, I don't want the most derived class to call the virtual base class constructor. [/edit]

Consider the following situation (not represented in the code example above):

  A
 / \
B0  B1
 \ /
  C
  |
  D  

I understand why C has to call the ctor of A (ambiguity) when you instantiate C, but why does D have to call it when instantiating D?

解决方案

Unfortunately, you will always have to call the virtual base classes constructor from the most derived class.

This is because you are saying that the virtual base is shared between all classes that derive from it for the instance of the object. Since a constructor may only be called once for a given instaniation of an object, you have to explicitly call the constructor in the most derived class because the compiler doesn't know how many classes share the virtual base (paraphrased (probably poorly) from The C++ Programming Language 3rd edition, section 15.2.4.1). This is because the compiler will start from the most base class's constructor and work to the most derived class. Classes that inherit from a virtual base class directly, will not, by the standard, call their virtual base classes constructor, so it must be called explicitly.

这篇关于调用虚拟基类的重载构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆