Vlad
Vlad

Reputation: 8585

C++ behavior of a default(implicit) copy constructor in a derived class

I have a question about the behavior of default copy constructor. For example, a class like this:

class A{
public:
    A(){}
    A(const A& a){}
    ~A(){}
    void foo(){}
};
class B:public A{
    public:
    B(){}
    B(const B& b){}
    B& operator=(const B& b){return *this;}
    ~B(){}
    virtual void foo(){}
};
class C:public B{
public:
    C(){}
    C& operator=(const C& c){a_=c.a_; return *this;}
    ~C(){}
    void foo(){}
protected:
    A a_;
};

if I will create a new object of class C like:

C* c1 = new C();

the steps would be:

  1. creating of A by explicit A()
  2. creating of B by explicit B()
  3. creating of A by explicit A() (protected member a_ in class C)
  4. creating of C by explicit C()

if I will initialize a new object of class C like:

    C c2(*c1);

it will invoke the default copy construcor of C. As far as I know, the steps would be:

  1. calling implicit copy constructor of class C
  2. It invokes explicit A(). Why not the A(const A& a)?
  3. explicit B(const B& b). Why not by B() like the base class A?
  4. Than it will finally invoke explicit A(const A& a) for protected member in class C a_. What is the difference this time? Why now it is a copy c'tor
  5. explicit C& operator=(const C& c) being called. Why does it invoke operator=? As far as I know, copy constructor is used when we initializing a new object and not the assignment operator
  6. A(const A& a) being called for a_ = c.a_ (in body of C& operator=)

How the default copy constructor behaves? What rules does it have?

I tried to search the implementation of a default copy constructor on the internet but I didn't find something that explains this behavior. Can anyone suggest something to read about this issue?

Upvotes: 2

Views: 2756

Answers (2)

David
David

Reputation: 28178

When you have a derived class copy constructor such as...

C(const C& c) {...}

You might think this would call A's and B's copy ctors automatically, but it doesn't. The implicit behavior is as if you had written...

C(const C& c) : B() {...}

... And then B's B() does...

B() : A() {...}

If you want copy ctors to be called up to your base classes you need to explicitly specify that behavior like so...

C(const C& c) : B(c) {...}

Implicitly generated copy ctors already do this for you.

As far as your observation that operator= is called in your situation, it isn't. I don't know why you think it is.

Upvotes: 4

user5106417
user5106417

Reputation:

Compile and run, check the comments in the code, it will be more clear:

#include <iostream>

class A{
public:
    A()
    {

    }
    A(const A& a)
    {
        std::cout << "Copy constructor FOR A is being called" << std::endl;
    }
    virtual ~A(){}
    void foo(){}
};

class B : public A
{
public:
    B()
    {

    }
    B(const B& b)
    {
        std::cout << "Copy constructor FOR B is being called" << std::endl;
    }
    B& operator=(const B& b){return *this;}
    virtual ~B()
    {

    }
    virtual void foo(){}
};

class C : public B
{
public:
    C()
    {

    }

    //if you remove this copy constructor, instead of only C being called, both A and B's copy constructor will be called
    C(const C& c)
    {
        std::cout << "Copy constructor FOR C is being called" << std::endl;
    }

    C& operator()(const C& c)
    {
        std::cout << "Operator is being called" << std::endl;
        a_=c.a_;
        return *this;
    }

    ~C()
    {

    }
    void foo()
    {

    }
protected:
    A a_;
};

int main()
{
    C* c = new C();
    C c2(*c); //copy constructor C will be called since we declared one, otherwise both A's and B's copy constructor would be called
    c2(c2); //here the operator() will be called but not above, changed that one to operator() since operator= didn't make sense
    delete c;

    std::cin.get();
    return 0;
}

Upvotes: 0

Related Questions