钻石问题初始化 - 默认构造函数被忽略?

buz*_*sin 1 c++ diamond-problem c++17

可能重复的:

考虑以下示例:

#include <iostream>
#include <cassert>

struct MyEnum {
    enum valid { CASE1, CASE2, DEFAULT };
    valid value;
    MyEnum(valid value = DEFAULT) : value(value) {}
};

class Base {
protected:
    MyEnum value;

public:
    Base() = default;
    Base(MyEnum value) : value(value) {
        std::cout << "Base::Base(MyEnum).\n";
    }  
};

class ReadableBase : public virtual Base {
public:
    ReadableBase() = default;
    ReadableBase(MyEnum value) : Base(value) {
        std::cout << "ReadableBase::ReadableBase(MyEnum).\n";
    }

public:
    MyEnum read() { return value; }
};

class WriteableBase : public virtual Base {
public: 
    WriteableBase() = default;
    WriteableBase(MyEnum value) : Base(value) {
        std::cout << "WriteableBase::WriteableBase(MyEnum).\n";    
    }

public:
    void write(MyEnum value) { this->value = value; }
};

class ReadWriteBase : public ReadableBase, 
                      public WriteableBase {
public:
    ReadWriteBase() = default;
    ReadWriteBase(MyEnum value) : ReadableBase(value), WriteableBase(value) {}
};

int main(int, char*[]) {
    // Incorrectly initialised with value = MyEnum::valid::DEFAULT
    ReadWriteBase rw(MyEnum::valid::CASE1);
    
    // Everything is okay now.
    rw.write(MyEnum::valid::CASE2);
}
Run Code Online (Sandbox Code Playgroud)

正如所演示的,尽管ReadWriteBase派生类接受MyEnum具有等效值 的,但程序报告和0 (= MyEnum::valid::CASE1)的值是。这似乎是因为根本没有被调用。ReadableBase::valueWriteableBase::value2 (= MyEnum::valid::DEFAULT)Base::Base(MyEnum)

assert(rw.ReadableBase::value  == MyEnum::valid::DEFAULT); // true
assert(rw.WriteableBase::value == MyEnum::valid::DEFAULT); // true
assert(rw.Base::value          == MyEnum::valid::DEFAULT); // true
Run Code Online (Sandbox Code Playgroud)

为什么会出现这种情况?我该如何正确地做到这一点?

额外问题:有没有更好的方法来解决这个问题?

Jar*_*d42 8

为什么会出现这种情况?我该如何正确地做到这一点?

虚拟基应该在最派生的类中初始化,所以应该是

class ReadWriteBase : public ReadableBase, 
                      public WriteableBase {
public:
    ReadWriteBase() = default;
    ReadWriteBase(MyEnum value) :
        Base(value),
        ReadableBase(value), // possibly ReadableBase()
        WriteableBase(value) // possibly WriteableBase()
    {}
};
Run Code Online (Sandbox Code Playgroud)