如何防止在基类初始值设定项中调用默认构造函数?

问题描述 投票:2回答:1

我试图构造Derived3,以便在d2初始化时调用非默认构造函数。我原本期望在d2初始化时,不会调用任何默认构造函数。使用此代码:

#include <string>
#include <iostream>

struct Base
{
    Base() : _message("Value initialized by default constructor")
    {
        std::cout << "Base default constructor called" << std::endl;
    }
    Base(std::string message) : _message(message)
    {
    }

    std::string     _message;
};

struct Derived1 : virtual public Base
{
    Derived1() : Base()
    {
        std::cout << "Derived1 default constructor called" << std::endl;
    }
    Derived1(std::string message) : Base(message)
    {   
    }

};

struct Derived2 : virtual public Base
{
    Derived2() : Base()
    {
        std::cout << "Derived2 default constructor called" << std::endl;
    }
    Derived2(std::string message) : Base(message)
    {
    }
};

struct Derived3 : virtual public Derived1, virtual public Derived2
{
    Derived3() : Derived1(), Derived2()
    {
        std::cout << "Derived3 default constructor called" << std::endl;
    }
    Derived3(std::string message) : Derived1(message), Derived2(message)
    {
    }
};

int main()
{
    Derived3 d1 = Derived3();
    std::cout << d1._message << std::endl; // You get what you expect.

    Derived3 d2 = Derived3("Not initialized by default constructor");
    std::cout << d2._message << std::endl; // You get what you do not expect.
}

我本以为d2._message会是"Not initialized by default constructor",实际上它是"Value initialized by default constructor"。完整输出是:

Base default constructor called
Derived1 default constructor called
Derived2 default constructor called
Derived3 default constructor called
Value initialized by default constructor
Base default constructor called
Value initialized by default constructor

预期产出:

Base default constructor called
Derived1 default constructor called
Derived2 default constructor called
Derived3 default constructor called
Value initialized by default constructor
Not initialized by default constructor

为什么会发生这种情况?如何实现预期的行为?

c++ oop inheritance initialization multiple-inheritance
1个回答
3
投票

当你虚拟地继承一个基类时,在所有情况下,虚拟继承的基类都可以被认为是所谓的“最派生”类的直接超类。更改您的Derived3构造函数如下:

Derived3(std::string message) : Derived1(message), Derived2(message),
                Base(message)

Base真的也是你的Derived3的基类,因为它几乎从Derived1(和Derived2)继承。这就是虚拟继承。

如果您不希望Base是默认构造的,那么您必须自己调用相应的构造函数。

即使你没有明确地声明Derived3继承自Base,它也会虚拟地继承它,因此你可以从Derived3调用它的构造函数。

请注意,如果您将Derived4声明为Derived3的子类,则此类Base的构造函数将不会被调用。 Derived4几乎将继承Base,它将负责构建它。

当你有几乎继承的类时,真正发生的是,你声明的每个构造函数都可以被认为实际上导致了两个实际的构造函数,实际上:一个构造函数负责构造所有虚拟继承的类,而构造函数则没有。你在上面声明的这个Derived3构造函数:你实际上最终得到了两个构造函数。两个价格为一个:一个将构建Base,一个不会。当Base直接构造时,将构造构造Derived3的那个,并且是最派生的类。第二个构造函数是相同的,除了它不会构造Base,并且如果Derived3的子类被实例化,它将被使用。您将其视为一个构造函数,但编译器执行了更多工作,创建了两个,并确保在需要构造某些内容时使用正确的编译器。

© www.soinside.com 2019 - 2024. All rights reserved.