Pravej Khan
Pravej Khan

Reputation: 152

Copy constructor for the class in C++

I want to write a copy constructor for the Plane class.

class Widget{ };
class Button: public Widget{};
class Label: public Widget {};
class Plane {
   vector<Widget*>vec;
public:
   void Add (Widget* w) {
      vec.push_back(w);
   }
// need to implement copy constructor for this class???
//Plane (const Plane &obj) ???
~Plane() {
   for (auto w: vec) {
      delete w;
     }
  }
};

int main () {
   Plane p1;
   p1.Add(new Button);
   p1.Add(new Label);
   Plane p2(p1);
   return 0;
}

Need your help to write a copy constructor for class Plane. Do I also need to change something in the Widget class as well? I want to have a deep copy and that's why a copy constructor is required here. I tried to write the copy constructor by myself but failed.

Upvotes: 2

Views: 178

Answers (1)

Giogre
Giogre

Reputation: 1504

I don't know why you decided to use raw pointers instead of unique_ptrs.

unique_ptrs have RAII functionality, meaning when going out of scope they automatically destroy, along with the pointer, the resource pointed-to.

With raw pointers instead, you are required to delete them manually. In addition, if you employ them as data members in a custom class, you are also required to define your own copy&move constructors and assignment operators.

A clone() method (which in Java I hear is infamous, much less so in C++) would allow you to perform deep copy of the vector<Widget*> as you require for your code.

The program should work if modified as below:

#include <iostream>
#include <vector>
#include <utility>
#include <stdexcept>

using std::cout;
using std::vector;
using std::move;
using std::exception;
using std::logic_error;

class Widget
{
public:
    Widget() {cout << "created Base Widget\n";}
    Widget(const Widget& original) noexcept {
        cout << "copied Base Widget\n";
    }

    virtual ~Widget(){} // need virtual destructor with class hierarchy

    virtual Widget* clone() const { // makes deep copies of pointers
        if constexpr(noexcept(Widget(*this))) {
            try {
                cout << "cloned Widget\n";
                return new Widget(*this);
            } 
            catch(exception& e) {
                throw runtime_error("error occurred while cloning Widget");
            }
        } else 
            throw logic_error("Widget: Faulty constructor");           
    }
};

class Button: public Widget{
public:
    Button(): Widget() { cout << "created Button\n"; }
    Button(const Button& original) noexcept: Widget(original){ 
        cout << "copied Button\n";
    }
    
    virtual Button* clone() const {
        if constexpr(noexcept(Button(*this))) {
            try {
                cout << "cloned Button\n";
                return new Button(*this);
            } 
            catch(exception& e) {
                throw runtime_error("error occurred while cloning Button");
            }
        } else 
            throw logic_error("Button: Faulty constructor");           
    }
    
    virtual ~Button(){}
};

class Label: public Widget {
public:
    Label(): Widget() { cout << "created Label\n"; }
    Label(const Label& original) noexcept: Widget(original){
        cout << "copied Label\n";
    }
    
    virtual Label* clone() const {
        if constexpr(noexcept(Label(*this))) {
            try {
                cout << "cloned Label\n";
                return new Label(*this);
            } 
            catch(exception& e) {
                throw runtime_error("error occurred while cloning Label");
            }
        } else 
            throw logic_error("Label: Faulty constructor");
    }
    
    virtual ~Label(){}
};

class Plane { // destructor is needed so copy&move semantics are also needed
              // (rule of 5)
    vector<Widget*>vec;
public:
    Plane(): vec(0) {}

    Plane(const Plane& original)  // performs deep copy
    {   
        vec.resize(original.vec.size());
        for (size_t i = 0; i != original.vec.size(); ++i) 
            vec[i] = original.vec[i]->clone();
    }

    Plane& operator=(const Plane& original)
    {   
        if (this != &original) {
            vec.resize(original.vec.size());
            for (size_t i = 0; i != original.vec.size(); ++i) 
                vec[i] = original.vec[i]->clone();
        }

        return *this;
    }

    ~Plane() {
        for (auto w: vec) {
            delete w;
            cout << "deleted Widget\n";
        }
    }

    // for completeness also add move semantics
    Plane(Plane&& original) noexcept
    {
        vec = move(original.vec);
        cout << "moved Plane\n";
    }

    Plane& operator=(Plane&& original) noexcept
    {
        if (this != &original)
            vec.swap(original.vec);

        return *this;
    }

    void Add (Widget* w) {
        vec.push_back(w);
        cout << "added Widget*\n";
    }
};

int main () {
   Plane p1;
   p1.Add(new Button);
   p1.Add(new Label);
   Plane p2(p1);
   
   return 0;
}

Results as expected: four Widgets are deleted (two in p1 and two in p2)

created Base Widget
created Button
added Widget*
created Base Widget
created Label
added Widget*
cloned Button
copied Base Widget
copied Button
cloned Label
copied Base Widget
copied Label
deleted Widget
deleted Widget
deleted Widget
deleted Widget

Upvotes: 2

Related Questions