Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call copy constructor of all base classes for copying most derived class object in diamond inheritance in C++?

Consider the below code:

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

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

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

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

int main()
{
   D d1;
   cout << "\n";
   D d(d1);
}

The output of the program is below:

1357
1358

So, for line D d(d1) the copy constructor of D class is bein called. During inheritance we need to explicitly call copy constructor of base class otherwise only default constructor of base class is called. I understood till here.

My Problem:

Now I want to call copy constructor of all base classes during D d(d1) execution. For that if I try below D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";} Then I get this error: error: 'class A A::A' is inaccessible within this context

How to resolve the issue. I want copy constructor of A, B and C when copy constructor of D gets called. It might be very small change but I am not getting.

like image 654
Gaurav Avatar asked Apr 30 '17 05:04

Gaurav


People also ask

Can copy constructor be inherited?

Copy constructor is not inherited.

How do you call a base class constructor from a derived class?

Whenever the derived class's default constructor is called, the base class's default constructor is called automatically. To call the parameterized constructor of base class inside the parameterized constructor of sub class, we have to mention it explicitly.

How can you overcome the diamond problem in inheritance?

The Diamond Problem is fixed using virtual inheritance, in which the virtual keyword is used when parent classes inherit from a shared grandparent class. By doing so, only one copy of the grandparent class is made, and the object construction of the grandparent class is done by the child class.

How can you pass parameters to the constructors of base classes in multiple inheritance?

To pass arguments to a constructor in a base class, use an expanded form of the derived class' constructor declaration, which passes arguments along to one or more base class constructors. Here, base1 through baseN are the names of the base classes inherited by the derived class.


1 Answers

First, lets change your inheritance as currently it is private:

class B : virtual protected A {...};
class C : virtual protected A {...};

Now, in your copy constructor, explicitly specify that the copy constructors of A and B and C should be called:

class D : protected B, protected C {
    D(const D & obj) : A(obj), B(obj), C(obj) {cout << "8";}
};

And the output will be as desired (2468).

Why?

When we have virtual base classes, they must be initialized by the most derived class, otherwise there would be ambiguity concerning whether B or C for example is responsible for the construction of A.

§12.6.2, (13.1):

In a non-delegating constructor, initialization proceeds in the following order:

  • First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

In particular, if you define a copy constructor, and omit the list of copy constructors it should call, then the default constructors will be used.

like image 114
donkopotamus Avatar answered Sep 18 '22 08:09

donkopotamus