2

Example of using virtual inheritance

class AA
{
public:
    AA() { cout << "AA()" << endl; };
    AA(const string& name, int _a):n(name),a(_a) {};
    AA(const AA& o) :n(o.n), a(o.a) {};
    virtual ~AA() { cout << "~AA()" << endl; };
protected:
    int a = 0;
    std::string n;
};

class A1 : public virtual AA
{
public:
    A1(const string& s) : AA(s, 0){}
};

class A2 : public virtual AA
{
public:
    A2(const string& s) : AA(s, 0) {}
};

class B : public A1, public A2
{
public:
    B(const string& a1, const string& a2) : A1(a1), A2(a2){}
    void test()
    {
        cout << A1::n << endl;
        cout << A2::n << endl;
    }
};

void test()
{
    B b("abc", "ttt");
    b.test();
}

Ideally, A1::n would be "abc" and A2::n would be "ttt". But they are both empty. Only AA() will be called once during the entire process.

enter image description here

What did I do wrong?

digito_evo
  • 3,216
  • 2
  • 14
  • 42
Zhang
  • 3,030
  • 2
  • 14
  • 31
  • 1
    Since you've made `AA` a `virtual` base, `A1::n` and `A2::n` are the same `std::string`. So they can't be different. The reason they are empty is that `B`s constructor needs to explicitly initialise the `virtual` base `AA` i.e. `B(const string& a1, const string& a2) : AA(a1), A1(a1), A2(a2){}`. Note that the construction of the virtual base happens BEFORE construction of `A1` and `A2` (and it is not constructed again in the process of constructing `A1` and `A2`). – Peter Jan 20 '22 at 09:38

2 Answers2

2

I was stupid. What virtual inheritance mean is to make the member become one. What I really want is just 2 copies of the members, just eliminate virtual.

class A {
protected:
    int a = 10;
public:
    A(int i):a(i){}
    virtual ~A(){}
};
class A1 : public /*virtual*/ A
{
public:
    A1(int i) :A(i) {};
};
class A2 : public /*virtual*/ A
{
public:
    A2(int i) :A(i) {};
};
class B : public A1, public A2
{
public:
    B(int a1, int a2): A1(a1), A2(a2) {}
    void test()
    {
        cout << A1::a << endl;
        cout << A2::a << endl;
    }
};
void test()
{
    B(1, 2).test();
    cout << sizeof(B);
}
Zhang
  • 3,030
  • 2
  • 14
  • 31
  • 1
    Side note: virtual base class constructor is called only from the most derived class, B in your case: [link](A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.). Thus, in your case it should be sth like that: `B(int a1, int a2): AA("abc", a1), A1(a1), A2(a2) {}`. As your code didn't call it explicitly, the default one was used. – alagner Jan 20 '22 at 07:59
0

The result is correct, while the real reason is when you are using virtual inheritance, D ctor first uses AA's default ctor, n is not assigned. If you want to use AA(name, a), you need to explicitly use that in D.

BUG CTOR
  • 31
  • 1