I have 3 classes in a hierarchy (call it A, B, and C) where B extends A and C extends B. Class A has a constructor that takes a single argument. The definition of C requires that A's constructor to be called, so I attempted to do that by creating a constructor in B. However, the compiler is telling me that C's constructor must initialize both A and B. That seems counter-intuitive to me because it should really be initialized just once.
Here's the code to better illustrate the issue that I'm facing:
#include <iostream>
struct A {
A(std::string name) : name_(name) {
std::cout << "A ctor called: " << name << std::endl;
}
std::string name_;
};
struct B : virtual public A {
// This constructor is required or else subclasses cannot be constructed properly
B(std::string name) : A(name) {
std::cout << "B ctor called: " << name << std::endl;
}
};
struct C : virtual public B {
// ERROR: constructor for 'C' must explicitly initialize the base class 'A' which does not have a default constructor
// C() : B("hey") {}
// ERROR: constructor for 'C' must explicitly initialize the base class 'B' which does not have a default constructor
// C() : A("hey") {}
// ok... but have to pass the same name twice & init'ed twice!
C() : A("wat"), B("hey") {
std::cout << "C ctor called" << std::endl;
}
// gcc reorders the constructor invocations...
// here it's written as B then A but it would be init'ed in the order of A then B
// C() : B("hey"), A("wat") {
// std::cout << "C ctor called" << std::endl;
// }
// ok... we can just pass a name but it's still init'ed twice!
// C(std::string name) : B(name), A(name) {}
};
int main() {
C c;
std::cout << c.name_ << std::endl;
}
When I run the code, I got:
A ctor called: wat
B ctor called: hey
C ctor called
wat
My questions are:
Is there a cleaner way to write it such that I don't have to call into both A & B's constructor explicitly?
Why does the output shows
heybeing set at a later time but thename_field containswat(which was set earlier)?