#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);
}
As demonstrated, despite the ReadWriteBase
derived class accepting the MyEnum
with the equivalent value of 0 (= MyEnum::valid::CASE1)
, the program reports that the value of ReadableBase::value
and WriteableBase::value
is 2 (= MyEnum::valid::DEFAULT)
. This appears to be because Base::Base(MyEnum)
is not called at all.
assert(rw.ReadableBase::value == MyEnum::valid::DEFAULT); // true
assert(rw.WriteableBase::value == MyEnum::valid::DEFAULT); // true
assert(rw.Base::value == MyEnum::valid::DEFAULT); // true
Why does this happen? How do I do this correctly?
Bonus question: Is there a better way to approach this problem?
Why does this happen? How do I do this correctly?
virtual base should be initialized in the most derived class, so it should be
class ReadWriteBase : public ReadableBase,
public WriteableBase {
public:
ReadWriteBase() = default;
ReadWriteBase(MyEnum value) :
Base(value),
ReadableBase(value), // possibly ReadableBase()
WriteableBase(value) // possibly WriteableBase()
{}
};