Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use base class Copy CTOR in derived class

Tags:

c++

oop

I know there are many posts on the subject, but I couldn't find any to fully answer my questions.

Say I have a Base class and a Derived class, which I implemented a CCtor and an assignment operator for it, something like the following:

class Base {
    char * name;
    ....
    Base(const Base& other) :name(nullptr) { *this = other }
    void operator=(const Base& other) { ... Deep copy of name } 
}


class Derived : public Base {
.... 
    Derived(const Derived& other) { *this = other ; }
    void operator=(const Derived& other) {
        Base::operator=(other);
        .....
    }

Now I have some questions about this design.

  1. Is this the right design for the situation?
  2. If i have a third class, between the base and the derived class, but it only contains primitive types, where shoud I copy them ? E.G. use the default assignment operator of the second class ? build a new one? only copy them on the third level ?
  3. I could similary call the base class CCtor inside the derived class CCtor, instead of the assignment operator. What's the difference? If I place them in both methods will it try to copy the values two times?

Edit: Just to clarify, the design is what I was given in my project .. I have pointers so I have to use a deep copy .

like image 970
sagi Avatar asked May 30 '18 14:05

sagi


1 Answers

Is this the right design for the situation?

No, not usually. The more idiomatic approach is to stop manually managing memory like char* name and use std::string or another type that does the right thing:

Class Base {
    std::string name;
    ....
    Base(const Base& other) = default;
    Base& operator=(const Base& other) = default;
};

(Note that assignment operators should return a reference to the class, not void).

Or encapsulate the memory management in a class design specifically for that purpose (but std::string already is that type).

If you really really need to do it the dumb error-prone way, then implement your copy constructor to do copying:

    Base(const Base& other) { / * deep copy of name */ }

Then implement assignment as copy-and-swap:

    Base& operator=(const Base& other)
    {
      Base tmp(other);
      this->swap(tmp);
      return *this;
    }

This means you need a cheap, non-throwing swap(Base&) member function.

In any case the derived type copy constructor is just silly. You have a correct copy constructor for the base class so it should be:

Derived(const Derived& other) : Base(other) { }

And the assignment can use the base assignment:

Derived& operator=(const Derived& other)
{
   Base::operator=(other);
   return *this;
}

But writing these manually is unnecessary, you can just default its copy operations which will Do The Right Thing anyway:

class Derived : public Base {
public:
    Derived(const Derived&) = default;
    Derived& operator=(const Derived& ) = default;

If i have a third class, between the base and the derived class, but it only contains primitive types, where shoud I copy them ? E.G. use the default assignment operator of the second class ? build a new one? only copy them on the third level ?

You should define the copy constructor and assignment operator of that class using = default as well. Once you've made Base safe to copy with correct behaviour, composing other classes to use it is trivial. The default behaviour will Do The Right Thing. You only need to define those operations manually if you need special treatment for something like dynamically-allocated memory that isn't being correctly managed by an RAII type.

I could similary call the base class CCtor inside the derived class CCtor, instead of the assignment operator. What's the difference?

If you want to copy construct then use the copy constructor, not assignment. Use the right function for the job.

like image 180
Jonathan Wakely Avatar answered Sep 23 '22 16:09

Jonathan Wakely