copy constructor

Pages: 12
Lets say you have an abstract class of such:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class vehicle
{
//abstract class
};

class car:vehicle
{
//does whatever
}
class bike:vehicle
{
//does whatever
}
class truck:vehicle
{
//does whatever
}


Lets say you have a person class having a 1:1 relationship such that 1 person owns only 1 vehicle.

1
2
3
4
5
class Person
{
public:  
vehicle *v;
}


how would implement the copy constructor for this class as you will never know what new object type has been created?

my answer: create a enum{car,bike,truck};
and have a method in vehicle class that has settype(int type) and int gettype();
with this Person class will check what type has been set and will create an object of that type. But i also see a issue with this solution. It wont excatly be a copy constructor, all it does is create a object of that type with default parameters.

Any possible ideas.
Last edited on
Does the person have the same vehicle or another (new) vehicle? In the first case, you don't need to do anything. In the latter case, you can create a virtual function called, say, "clone()" in each of the classes that properly construct the new object as a copy of the one you started with.
the person has a new vehicle type and another person needs to copy the exact configuration.

eg:
1
2
3
4
5
6
7
8
9
10
11
main()
{
 Person p;
 
p.v = new car;

(p.v)->blah();

Person q = p;//i want all the configuration to be copied to q

} 
Last edited on
However based on the clone pattern it assumes that Base is not an abstract class. What if base is an abstract class meaning no instance of base can be created. In my example above, lets say i take an instance of a car, how will I define q to copy p and I want to do a deep copy.
The clone pattern is exactly for deep copying abstract objects.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Vehicle
{
public:
  virtual Vehicle* clone() = 0;

  // ...
};

class Car
{
public:
  virtual Car* clone() { return new Car(*this); }

  //...
};

int main()
{
  Vehicle* a = new Car;  // a points to a Car

  // this will deep copy 'a' without knowing what child it points to:
  Vehicle* b = a->clone();
}
wow this is very interesting....I learn something new and cool but just a question....when we usually do a copy constructor we pass in the value as reference and do a copy of all its members, instead we could do this way by just :

1
2
3
4
Person(const Pesron &p)
{
this = p->clone();
}


edit: lets say Person class has a pointer that creates a new array;
int *ptr = new int[10];

could the above be done nstead of
1
2
3
4
5
Person(const Pesron &p)
{
ptr = new int[p.size()];
//then copy values...
}
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
7 class arr
  8 {
  9 
 10 int size;
 11 public:
 12         int* p;
 13         arr(int sz)
 14         {
 15                 size = sz;
 16                 p = new int[size];
 17         }
 18         ~arr(){delete[] p;}
 19         void set(){for(int i=0;i<size;i++)p[i] = i;}
 20      
 21         arr* clone(){return new arr(*this);}
 22         void disp(){for(int i=0;i<size;i++)cout<<p[i];cout<<endl;}
 23 };
 24 
 25 
 26 int main()
 27 {
 28         arr obj1(10);
 29         obj1.set();
 30         arr *obj2 = obj1.clone();
 31         obj1.disp();
 32         obj2->disp();
 33         
 34         delete obj2;
 35         obj1.disp();
 36         
 37         return 0;
 38 }     


This code shows that clone does not do a deep copy cause if i delete obj2, the entire heap is deleted and obj1 does a double free?
If you need to code the destructor, the copy constructor or the assignment operator, then you need to code all of them.

The clone is based on the copy constructor. But the one provided by the compiler does a shallow copy.
Last edited on
jackel7777 wrote:
when we usually do a copy constructor we pass in the value as reference and do a copy of all its members, instead we could do this way by just :


No, you are misunderstanding.

cloning deep copies a pointer, it doesn't replace a copy constructor. Furthermore you cannot assign this, so your example is incorrect.

Cloning is useful for objects that own a pointer to an abstract type. Like in your original example:

- Person owns a Vehicle*
- Vehicle is an abstract type

Therefore:

- Vehicle would need a clone() function
- Person would clone the vehicle in its copy ctor

The vehicle would not clone itself, nor would the person clone itself.


jackel7777 wrote:
This code shows that clone does not do a deep copy cause if i delete obj2, the entire heap is deleted and obj1 does a double free?


Cloning performs a deep copy of whatever you're cloning as long as the object properly copies itself. As ne555 mentioned, arr does not have a custom copy ctor to deep copy the 'p' member, therefore you have this problem.

Here, you are misusing the clone pattern. 'arr' is not abstract so there's no point to it. You might as well just call the copy ctor directly.



Let me put it this way. Cloning lets you deep copy a pointer when that point is abstract. Continuing with the original example of Vehicle/Car/Bike/Truck:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Vehicle* a = whatever;

// we want to deep copy 'a' to another pointer
//  without cloning, we'd have to do something like this:

Vehicle* b;

if( a_is_a_Car )
  b = new Car( *static_cast<Car*>(a) );
if( a_is_a_Bike )
  b = new Bike( *static_cast<Bike*>(a) );
if( a_is_a_Truck )
  b = new Truck( *static_cast<Truck*>(a) );

// .. etc (repeat for all possible types of vehicles 


Obviously this is a bad idea. Therefore we can just use the clone pattern:

1
2
3
4
Vehicle* a = whatever;

Vehicle* b = a->clone();  // doesn't matter what kind of Vehicle 'a' is
  //  by cloning it, 'b' will be the same kind of vehicle 


Note that Vehicle will still need to deep copy all of its members in its copy constructor. Cloning doesn't replace the need to implement copy constructors, it just let's you dynamically copy something without knowing its exact type.
Why don't you just have a function that returns the Type of class it is, so you know the correct way to deal with it at all times? This makes many other things easier too, such as things that you need to specifically know what you're dealing with to avoid issues.
Why don't you just have a function that returns the Type of class it is, so you know the correct way to deal with it at all times?


Because that's poor design and a maintenance nightmare.

Let's say you do that. Then to copy a vehicle you do something like this:

1
2
3
4
5
6
7
Vehicle* b = 0;
switch(a->GetType())
{
  case Type_Car:  b = new Car( static_cast<Car*>(*a) ); break;
  case Type_Bike:  b = new Bike( static_cast<Bike*>(*a) ); break;
  case Type_Truck:  b = new Truck( static_cast<Truck*>(*a) ); break;
}


Not only is this more code to write than the simple b = a->clone();, but it also only works if 'a' is one of those 3 types of vehicles.

What happens if you add a new vehicle... like Unicycle? Now you have to:

- Create a new ID for the Unicycle (Type_Unicycle)
- Make sure all IDs are unique
- Go back to every place in every program that checks the type of vehicle and have it check for Type_Unicycle. Depending on how heavily the class is used, this might be hundreds of places. Good luck finding all of them.



Good OOP keeps code "ignorant" about the specific kind of class you're using. The whole point of abstraction is that you write code that works with any class, so that when new classes are introduced, your code will just work with them automatically without you having to change anything.


This makes many other things easier too, such as things that you need to specifically know what you're dealing with to avoid issues.


It really doesn't. If you find yourself needing to check what kind of Vehicle you have, you're probably doing something wrong.
Shouldn't you be able to change the oil on a car and not a unicycle?
If your classes need to do that, they should probably be structured differently.

Perhaps:

1
2
3
4
5
6
7
class Vehicle {}; // abstract, no oil functions

class MotorizedVehicle : public Vehicle {}; // abstract + oil functions

class Car : public MotorizedVehicle {};  // can change the oil on a Car

class Unicycle : public Vehicle {}; // but not on a Unicycle 


Any code that would need to change the oil on something would then take a MotorizedVehicle* and not a Vehicle*.

That way, the code that changes the oil does not need to know whether or not it's changing the oil on a Car, Truck, etc. All it knows is that it's changing the oil on a motorized vehicle.
Last edited on
Ah, OK. Thanks Disch, and sorry for my interference in this thread.
Don't be sorry! You are not interfereing. You are encouraging discussion on an important topic! =)
closed account (zwA4jE8b)
What does 'deep copy' mean? Is there a shallow copy? What is that?
If you have a class that has a pointer to something, "deep copying" creates a copy of whatever that pointer points to, whereas "shallow copying" just copies the pointer itself.

Example:

1
2
3
4
5
6
7
MyClass* foo = new MyClass( ... );

// a deep copy:  Create a new object, copy all the data to the new object
MyClass* deep = new MyClass(*foo);

// a shallow copy:  Don't actually copy the data, just copy the pointer
MyClass* shallow = foo;
closed account (zwA4jE8b)
Oh ok, so its kind of synonymous with layers.
Cloning performs a deep copy of whatever you're cloning as long as the object properly copies itself

@disch

In my understanding, the clone() method creates a new object of the type passed in. But when one says you are doing a deep copy it means that you have allocated new memory on the heap and have copied each and every element of the object being copied from.

So by doing
1
2
Vehicle* a = whatever;
Vehicle* b = a->clone();


in the copy ctor of the Person how does that resort to deep copy when say vehicle a has done some car modification() and you need that to be reflected in vehicle b.

In the arr class, i did a clone() that would have created a new object just like it would have created a new object for the abstract method()...so why the difference?
Last edited on
Pages: 12