0

Although there are numerous posts with managing pointers in copy constructors, i did not find the suitable answer to realize the following properly.

An object 'a' of class A stores a 'tab' array of elements that are pointers to elements of either type B1 or B2, both derived from class B.

I want to save a copy of 'a' (to restore it later) by calling a copy constructor. My problem is to allocate memory in this copy constructor, to make a copy of the contents of the 'tab[i]' elements.

There must be a canonical way of doing this (i suppose without invoking <dynamic_cast> to determine if this is type B1 or B2).

This is the MWE i have build to illustrate the question:

#include <iostream>
using namespace std;


//-----------------------
class B {
public:
  virtual void display()=0;
};

//-----------------------
class B1 : public B {
public:
  B1() : val(1)  // ctor
  {}  
  void display() {
    cout << val << endl;
  }
private:
  int val;

};
//-----------------------
class B2 : public B {
public:
  B2() : val(2)  // ctor
  {}
  void display() {
    cout << val << endl;
  }
private:
  int val;

};

//---------- A -------------
class A {

public:
  A () {            // ctor
    tab = new B * [2];
    tab[0] = new B1;
    tab[1] = new B2;
  } 

  A (A const &orig)         // copy ctor
    : tab(orig.tab)
  {          
    // ... HOW should i make a copy of the tab[i] elements ?...
    // ... as i do not know if tab[i] is type B1 or B2 ...
  }

  void display() {
    tab[0]->display();   
    tab[1]->display();   
  }


private:
  B ** tab;
};




//------M A I N ---------

int main() {
  A a;
  a.display();

  return 0;
}
user1551605
  • 166
  • 9
  • You need to look up the difference between a deep copy constructor and a shallow one. https://stackoverflow.com/questions/2657810/deep-copy-vs-shallow-copy – jiveturkey Mar 13 '18 at 16:38

1 Answers1

4

You cannot do this without determining the concrete type of B, either by using dynamic_cast, or by calling a virtual method, which is then dispatched to the concrete type.

This is typically resolved by using the "clone" pattern on the interface of B, adding the function to B: virtual B* clone() const = 0; with each implementation allocating and returning an appropriate copy of itself.

Also notice you are not deleting any of the memory allocated in your example. Remember to do this in destructors, or better use smart pointers like std::unique_ptr!

James Beilby
  • 1,362
  • 10
  • 9
  • Thanks! Now i'm sure the clone() pattern applies here. Note that i did not include deletion of allocated memory just to provide a minimal example that can build and display something. – user1551605 Mar 13 '18 at 16:57
  • Thought so re: minimal example. Yep unfortunately your instinct was right (fair amount of boiler plate code around doing cloning). – James Beilby Mar 13 '18 at 17:01