Skip to content
Search

C++:Inheritance

lastmod 2018-08-17created 2015-04-028 edits

Notes on inheritance in C++.

Virtual inheritance

An example that causes problems with multiple inheritance is as follows.

#include <iostream>
using namespace std;

struct A {
    int ii;
    A(int i) : ii(i) { cout << "A:" << i << endl; }
    void printFromA() { cout << "ii: " << ii << std::endl; }
};

struct B : public A {
    B(int i) : A(i) { cout << "B:" << i << endl; }
    void printFromB() { cout << "ii: " << ii << std::endl; }
};

struct C : public A {
    C(int i) : A(i) { cout << "C:" << i << endl; }
    void printFromC() { cout << "ii: " << ii << std::endl; }
};

struct D : public B, public C {
    D(int b, int c) : B(b), C(c) { cout << "D:" << b << "," << c << endl; }
    // void printFromD() { cout << "ii: " << ii << std::endl; } // ambiguous error.
};

int main()
{
    D d(1, 2);
    //d.printFromA(); // ambiguous error.
    d.printFromB();
    d.printFromC();
    return 0;
}

As shown below, the A constructor is called twice. (B and C each hold their own separate A.)

A:1
B:1
A:2
C:2
D:1,2
ii: 1
ii: 2

To solve this, apply virtual inheritance. (The unneeded print~ functions are removed.)

#include <iostream>
using namespace std;

struct A {
    A(int i) { cout << "A:" << i << endl; }
};

struct B : virtual public A {
    B(int i) : A(i) { cout << "B:" << i << endl; }
};

struct C : virtual public A {
    C(int i) : A(i) { cout << "C:" << i << endl; }
};

struct D : public B, public C {
    D(int b, int c) : B(b), C(c) { cout << "D:" << b << "," << c << endl; }
};

int main()
{
    D d(1, 2);
    return 0;
}

Doing it this way produces the following error.

test.cpp: In constructor ‘D::D(int, int)’:
test.cpp:30:32: error: no matching function for call to ‘A::A()’
     D(int b, int c) : B(b), C(c)
                                ^
test.cpp:6:5: note: candidate: A::A(int)
     A(int i)
     ^
test.cpp:6:5: note:   candidate expects 1 argument, 0 provided
test.cpp:4:8: note: candidate: A::A(const A&)
 struct A
        ^
test.cpp:4:8: note:   candidate expects 1 argument, 0 provided

The virtual keyword is a keyword for late binding. So the inheritance does not happen in B and C, but through D. Therefore it must finally be changed as follows.

#include <iostream>
using namespace std;

struct A {
    A(int i) { cout << "A:" << i << endl; }
};

struct B : virtual public A {
    B(int i) : A(i) { cout << "B:" << i << endl; }
};

struct C : virtual public A {
    C(int i) : A(i) { cout << "C:" << i << endl; }
};

struct D : public B, public C {
    D(int b, int c) : A(100), B(b), C(c) { cout << "D:" << b << "," << c << endl; }
};

int main()
{
    D d(1, 2);
    return 0;
}

The initialization code A(100) was added to the D constructor. The output is as follows.

A:100
B:1
C:2
D:1,2

Non inheritance policy

class SomeClass : private virtual boost::noncopyable
{
public:
//< virtual 키워드는 구현 코드의 지연을 의미한다. 따라서 실제 객체를 선언할때에 판별 될 것이다.
};

For reference, in C++11 this is easily solved with final.

class CBase final
{
...
};

Troubleshooting

virtual-move-assign

GCC may produce the following error.

defaulted move assignment for 'B' calls a non-trivial move assignment operator for virtual base 'A' [-Wvirtual-move-assign]

Here is an example.

struct Base
{
    Base() = default;
    Base& operator=(Base&&)
    {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        return *this; 
    }
};

struct A : virtual Base {};

struct B : virtual Base {};

struct C : A, B {};

int main()
{
    C c;
    c = C();
}

The output is as follows:

Base& Base::operator=(Base&&)
Base& Base::operator=(Base&&)

This shows that the single Base instance was moved twice, once by each of the move assignment operators of A and B. The second move assignment takes from an already moved-from object and can overwrite the contents of the first move assignment. Clang emits a warning related to -Wmultiple-move-vbase. The way to fix this is to implement move assignment operators for A and B so that they detect that Base has already been moved and skip the second move assignment.

Favorite site