Search code examples
c++classoopconstructorvirtual-functions

How can I print "ABCDabcd" with these class constructors?


I have the following code:

#include <iostream>
using namespace std;
    
class A {
public:
    A() { cout << "A"; }
    A(const A&) { cout << "a"; }
};

class B : public virtual A {
public:
    B() { cout << "B"; }
    B(const B&) { cout << "b"; }
};

class C : public virtual A {
public:
    C() { cout << "C"; }
    C(const C&) { cout << "c"; }
};

class D : B, C {
public:
    D() { cout << "D"; }
    D(const D&) { cout << "d"; }
};

And I want to create a D object and have it print "ABCDabcd".

I tried this:

int main()
{
    D d;
    return 0;
}

But it only prints "ABCD", and I don't know how to call the rest of the code.

Any idea?


Solution

  • The ABCD portion of the output you see is being printed by the default constructors of A, B, C, and D. When main() constructs the D object, it is invoking D's default constructor, which invokes A, B, and C's default constructors.

    The abcd portion of the output that is missing is printed by the copy constructors of A, B, C, and D instead. So main() needs to make a copy of the D object in order to invoke D's copy constructor, eg:

    int main()
    {
        D d;
        D d2{d}; // or: D d2 = d;
        return 0;
    }
    

    Online demo

    However, you will notice that the output of this copy will be ABCd rather than abcd as expected. This is because D's copy constructor does not invoke the copy constructors of A, B, or C, it invokes their default constructors instead.

    To fix that, you need to add a member initialization list to each copy constructor in order to call non-default base constructors, eg:

    class A {
    public:
        A() { cout << "A"; }
        A(const A&) { cout << "a"; }
    };
    
    class B : public virtual A {
    public:
        B() { cout << "B"; }
        B(const B &b) : A(b) { cout << "b"; }
    };
    
    class C : public virtual A {
    public:
        C() { cout << "C"; }
        C(const C &c) : A(c) { cout << "c"; }
    };
    
    class D : public B, C {
    public:
        D() { cout << "D"; }
        D(const D &d) : A(d), B(d), C(d) { cout << "d"; }
    };
    

    Then the copy will print abcd as expected.

    Online demo