本文介绍了为什么在较老的祖先已有的规则中,在最派生类的初始化列表中显式调用虚拟基类构造函数的规则?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码:

#include<iostream>
using namespace std;

class Man
{
    int stories;

public:
    Man(int stories) : stories(stories) {cout << "A man is created with " << stories << " stories." << endl;};
};

class Grandpa : public virtual Man
{
    int pipes;

public:
    Grandpa(int stories, int pipes) : Man(1000), pipes(pipes)
    {
        stories += stories;
        cout << "Grandpa is created with " << stories << " stories and pipes." << endl;
    };
};

class Father : public Grandpa
{
    int cars;

public:
    Father(int stories, int cars) : Man(1000), Grandpa(1000, 1), cars(cars)
    {
        stories += stories;
        cout << "Father is created with " << stories << " stories and cars." << endl;
    };
};

class Son : public Father
{
    int girls;

public:
    Son(int stories, int girls) : Man(1000), Father(1000, 3), girls(girls)
    {
        stories += stories;
        cout << "Son is created with " << stories << " stories and girls." << endl;
    };
};

int main()
{
    Son Dick(1000, 5);
    return 0;
}

在运行中提供以下输出:

Gives the following output on the run:

创建了一个拥有1000个故事的男人.

爷爷是用2000个故事和烟斗创建的.

父亲是由2000个故事和汽车组成的.

儿子由2000个故事和女孩组成.

当我不在父亲和儿子的初始值设定项列表中调用Man(int)时,它将无法编译.它正在尝试调用Man(void),而Man()未定义.为什么会这样呢?但是,我认为,当调用父亲或儿子的构造函数时,虚拟库的构造函数已经在爷爷中被调用了!而且因此,我希望输出为:

And it does not compile, when I do not call Man(int) in Father's and Son's initializers' lists. It is trying to call Man(void), and Man() is not defined. Why is it so? Yet, I think, when Father's or Son's constructors were called, the virtual base's constructor had already been called in Grandpa! Moreover thus, I would expect the output to be:

创建了一个拥有1000个故事的男人.

爷爷是用2000个故事和烟斗创建的.

父亲是由3000个故事和汽车组成的.

儿子由4000个故事和女孩组成.

然后概括一下:为什么虚拟基类构造函数必须在派生类的初始化列表中显式调用,尽管它已被放置在较年轻的祖先初始化列表中?为什么在年轻的祖先中似乎没有调用它,而尝试调用默认的基类呢?

To recapitulate then: why a virtual base class constructor has to be called explicitly in an initializer list of a derived class, although it is already placed in an younger's ancestor initializer list? Why it is seemingly not called in the younger ancestor, and a default base class is tried to be called instead?

编辑,因为找到了数字问题的答案真可惜:)我本应该在爷爷protected int _stories;中创建int stories,然后输出将如预期的那样:男人的故事为1000个,爷爷的故事为2000个,父亲的故事为3000个,迪克的故事为4000个:)本地变量而不是Man的成员...对不起,麻烦您了!

EDIT due to finding an answer to problem with numbersWhat a shame :) I should have made int stories in Grandpa protected int _stories; and then the output would be as expected: 1000 stories for Man, 2000 for Grandpa, 3000 for Father and 4000 for Dick :) Otherwise stories += stories acts on local variable instead of the Man's member... Sorry for bothering!

推荐答案

对虚拟基础的构造函数的调用来自于所创建对象的最派生类型.在这种情况下,它是Son,因此Son需要调用Man的构造函数.

The call to the virtual base's constructor comes from the most-derived type of the object being created. In this case, that's Son, so Son needs to call Man's constructor.

但是,也可以创建实际上不是SonFather(例如,具有Father Dick(1000, 5)main).因此,Father可能最终成为初始化Man的对象,这意味着它需要调用Man的构造函数. Grandpa也是一样.

However, it's also possible to create a Father that isn't actually a Son (e.g., main having Father Dick(1000, 5)). Because of that, Father might end up being the one to initialize Man, meaning it needs to call Man's constructor. The same is true for Grandpa.

如果创建ManGrandpaFather抽象类,则它们不再可能是初始化Man的类,因此不需要调用其构造函数.但是,当我这样做时(Glang编译它),GCC 6.1给了我一个错误.我相信海湾合作委员会在这里是错的.

If you make Man, Grandpa, and Father abstract classes, they can no longer possibly be the ones to initialize Man, and thus do not need a call to its constructor. However, GCC 6.1 gives me an error when I do this (Clang compiles it). I believe GCC to be wrong here.

这篇关于为什么在较老的祖先已有的规则中,在最派生类的初始化列表中显式调用虚拟基类构造函数的规则?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-24 17:14