473,385 Members | 1,958 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

virtual copy constructor

I have been plunging my brains trying to figure this out all day today...Its 2 am now. Please, someone explain the following to me: I know the virtual clone method is there in each class to facilitate the use of virtual copy constructors since you cannot directly declare
*virtual Mammal (const Mammal & rhs);* in this manner. However, I cannot understand what the clone method is doing. Lets say for example, at the prompt, I enter 2. Then the switch statement creates a Cat object on the free store and assigns it to ptr. Then ptr is assigned to theArray[i]. This cycle continues until the for loop ends. Then it executes the next for loop with the addresses stored in theArray[i] accessing the speak method. you see "Meow" in the output. In the next step it access the clone method and the both the Cat copy constructor and the Dog copy constructor is called. How is this possible? And what are the steps taking place here? How does the Cat's clone method call the copy constructors? It is possible that I am not understanding the fundamentals of *this as I suspect that this is responsible for calling the copy constructor.

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5.  class Mammal
  6.  {
  7.  public:
  8.  Mammal():itsAge(1) { cout << "Mammal constructor...\n"; }
  9.  ~Mammal() { cout << "Mammal destructor...\n"; }
  10.  Mammal (const Mammal & rhs); 
  11.  virtual void Speak() const { cout << "Mammal speak!\n"; }
  12.  virtual Mammal * Clone() { return new Mammal(*this); } 
  13.  int GetAge()const { return itsAge; }
  14.  protected:
  15.  int itsAge;
  16.  };
  17. //copy constructor defined
  18.  Mammal::Mammal (const Mammal & rhs):itsAge(rhs.GetAge())
  19.  {
  20.  cout << "Mammal Copy Constructor...\n";
  21.  }
  22.  
  23.  class Dog : public Mammal
  24.  {
  25.  public:
  26.  Dog() { cout << "Dog constructor...\n"; }
  27.  ~Dog() { cout << "Dog destructor...\n"; }
  28.  Dog (const Dog & rhs); 
  29.  void Speak()const { cout << "Woof!\n"; }
  30.  virtual Mammal * Clone() { return new Dog(*this); } 
  31.  };
  32.  
  33.  Dog::Dog(const Dog & rhs):
  34.  Mammal(rhs)
  35.  {
  36.  cout << "Dog copy constructor...\n";
  37.  }
  38.  
  39.  class Cat : public Mammal
  40.  {
  41.  public:
  42.  Cat() { cout << "Cat constructor...\n"; }
  43.  ~Cat() { cout << "Cat destructor...\n"; }
  44.  Cat (const Cat & rhs); 
  45.  void Speak()const { cout << "Meow!\n"; }
  46.  virtual Mammal * Clone() { return new Cat(*this); } 
  47.  };
  48.  
  49.  Cat::Cat(const Cat & rhs):
  50.  Mammal(rhs)
  51.  {
  52.  cout << "Cat copy constructor...\n";
  53.  }
  54.  
  55.  enum ANIMALS { MAMMAL, DOG, CAT}; 
  56.  const int NumAnimalTypes = 3; 
  57.  
  58.  int main()
  59.  {
  60.  Mammal * theArray[NumAnimalTypes]; 
  61.  Mammal * ptr; 
  62.  int choice, i;
  63.  for ( i = 0; i<NumAnimalTypes; i++)
  64.  { 
  65.  cout << "(0)Mammal (1)dog (2)cat: ";
  66.  cin >> choice;
  67.  
  68.  switch (choice)
  69.  {
  70.  case DOG: ptr = new Dog; 
  71.  break;
  72.  case CAT: ptr = new Cat; 
  73.  break;
  74.  default: ptr = new Mammal; 
  75.  break;
  76.  }
  77.  theArray[i] = ptr; 
  78.  }
  79.  Mammal * OtherArray[NumAnimalTypes]; 
  80.  
  81.  
  82.  for (i=0;i<NumAnimalTypes;i++)
  83.  {
  84.  theArray[i]->Speak(); 
  85.  OtherArray[i] + theArray[i]->Clone(); 
  86.  
  87.  }
  88.  
  89.  for (i=0;i<NumAnimalTypes;i++)
  90.  OtherArray[i]->Speak(); 
  91.  
  92.  system("pause");
  93.  return 0;
  94.  }
  95.  
Aug 12 '10 #1
10 2250
newb16
687 512MB
constructor - Dog::Dog(const Dog & rhs)
code - return new Dog(*this);
'this' variable here is a pointer to the class instance, of the type Dog*, then it is dereferenced to the type Dog& and passed to constructor. It works the same way as if they were
Expand|Select|Wrap|Line Numbers
  1. constructor - Dog::Dog(const Dog* rhs)
  2. code - return new Dog(this);
  3.  
Aug 12 '10 #2
weaknessforcats
9,208 Expert Mod 8TB
A clone is a copy.

In C++ you create a clone by using the copy constructor.

In languages other than C++ where there is notjhing like a copy constrcutor, you need to write a clone method to make the copy.
Aug 12 '10 #3
Thanks for the responses. But I am sorry, i'm still not getting the complete picture. Let me know if this is correct: in the virtual function:

virtual Mammal * Clone(){return new Dog(*this)}

It creates a Dog object on the free store and assigns the calling object's contents to this newly created Dog. Then it returns a pointer to a Mammal. Then this pointer is stored in OtherArray[i] which will iterate to display all the speak methods. A mammal pointer is able to access the correct speak methods in Dog, Cat, etc because the speak method in Mammal is virtual. Am I correct so far? Now, the question is: When in this process is the copy constructor called? And what is the copy constructor doing? I really think I should understand this before moving on to polymorphism.
Aug 12 '10 #4
newb16
687 512MB
Yes you are correct.

This part
> assigns the calling object's contents to this newly created Dog.

actually happens within copy constructor, when parent constructor is called -
Expand|Select|Wrap|Line Numbers
  1. : Mammal(rhs)
and copies the only member (age) from rhs into constructing object.
When is it called? During 'new' operator, after memory is allocated.
Aug 12 '10 #5
Thanks for the explanation newb16. I now understand that the new Dog gets its age copied to it inside the copy constructor. So when the Dog clone() method is called, I see 2 events take place:

1. A new Dog object is created on the free store.

In between these two steps, the Mammal copy constructor is called first with the address in *this and then the Dog copy constructors is called with *this. And inside the copy constructor, the value of age is copied into the new object. So basically *this is calling these copy constructors?

2. A Mammal pointer to this object is returned to the invoking object which is theArray[i] and the address is assigned to OtherArray[i].
Aug 13 '10 #6
I think I finally understand this correctly thanks to newb16 and others. Please see my comments in the code below and let me know if I my understanding is right or wrong. Thanks for your patience with my rather long comments.

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2.  
  3. using namespace std;
  4.  
  5.  class Mammal
  6.  {
  7.  public:
  8.  Mammal():itsAge(1) { cout << "Mammal constructor...\n"; }
  9.  ~Mammal() { cout << "Mammal destructor...\n"; }
  10.  Mammal (const Mammal & rhs); 
  11.  virtual void Speak() const { cout << "Mammal speak!\n"; } //virtual function
  12.  virtual Mammal * Clone() { cout << "mammal clone called" << endl; return new Mammal(*this); } //This method returns a pointer to a new Mammal
  13.  //object by calling the copy constructor, passing in itself (*this) as a const reference to a mammal. this virtual method is the core of the 
  14.  //copy constructor. Here is the step by step of what happens here:
  15.  //A Mammal object's ptr calls this method. A new Mammal is created on the heap. Then Mammal(*this) calls Mammal copy constructor. 
  16.  //*this contains a constant reference(address) of the new Mammal object. This address is assigned to rhs because it takes a reference(address).
  17.  //Then rhs gets the existing value in itsAge, and assigns it to the new Mammal object's itsAge. The clone method also returns a
  18.  //pointer to a Mammal back to the invoking object which is theArray[i] and the address is assigned to OtherArray[i]. Using this Mammal pointer,
  19.  //the correct speak method is called for each object in the end.
  20.  
  21.  
  22.  int GetAge()const { return itsAge; }
  23.  protected:
  24.  int itsAge;
  25.  };
  26.  
  27.  Mammal::Mammal (const Mammal & rhs):itsAge(rhs.GetAge())
  28.  {
  29.  cout << "Mammal Copy Constructor...\n";
  30.  }
  31.  
  32.  class Dog : public Mammal
  33.  {
  34.  public:
  35.  Dog() { cout << "Dog constructor...\n"; }
  36.  ~Dog() { cout << "Dog destructor...\n"; }
  37.  Dog (const Dog & rhs); 
  38.  void Speak()const { cout << "Woof!\n"; }
  39.  virtual Mammal * Clone() { cout << "dog clone called" << endl; return new Dog(*this); } //Step by step of what happens here:
  40.  //A Dog object calls the Dog clone method. Then Dog(*this) calls the Dog copy constructor and passes in the address of the new Dog object
  41.  //into rhs. Then this rhs(address of the new Dog object) is passed in as a reference to Mammal, thus Mammal(rhs) calls the 
  42.  //Mammal copy constructor that takes in a reference(address). Control is now passed to the Mammal copy constructor.   
  43.  //Now inside the Mammal copy constructor, rhs gets the existing value for age and assigns it into the new Dog object's itsAge.
  44.  //And then the Mammal body code is executed. Control now returns back to the Dog copy constructor. And then its body is executed.
  45.  //And then a pointer to the mammal is returned to the invoking object theArray[i].
  46.  };
  47.  
  48.  Dog::Dog(const Dog & rhs):
  49.  Mammal(rhs)
  50.  {
  51.  cout << "Dog copy constructor...\n";
  52.  }
  53.  
  54.  class Cat : public Mammal
  55.  {
  56.  public:
  57.  Cat() { cout << "Cat constructor...\n"; }
  58.  ~Cat() { cout << "Cat destructor...\n"; }
  59.  Cat (const Cat & rhs); 
  60.  void Speak()const { cout << "Meow!\n"; }
  61.  virtual Mammal * Clone() {cout << "cat clone called" << endl; return new Cat(*this); }  //same procedure as Dog's clone method.
  62.  };
  63.  
  64.  Cat::Cat(const Cat & rhs):
  65.  Mammal(rhs)
  66.  {
  67.  cout << "Cat copy constructor...\n";
  68.  }
  69.  
  70.  enum ANIMALS { MAMMAL, DOG, CAT}; 
  71.  const int NumAnimalTypes = 3; 
  72.  
  73.  int main()
  74.  {
  75.  Mammal * theArray[NumAnimalTypes];  
  76.  Mammal * ptr; 
  77.  int choice, i;
  78.  
  79.  for ( i = 0; i<NumAnimalTypes; i++)
  80.  { 
  81.  cout << "(0)Mammal (1)dog (2)cat: ";
  82.  cin >> choice;
  83.  
  84.  switch (choice)
  85.  {
  86.  case DOG: ptr = new Dog; 
  87.  break;
  88.  case CAT: ptr = new Cat; 
  89.  break;
  90.  default: ptr = new Mammal; 
  91.  break;
  92.  }
  93.  theArray[i] = ptr; 
  94.  }
  95.  Mammal * OtherArray[NumAnimalTypes]; 
  96.  
  97.  for (i=0;i<NumAnimalTypes;i++)
  98.  {
  99.  theArray[i]->Speak(); 
  100.  OtherArray[i] = theArray[i]->Clone(); 
  101.  
  102.  }
  103.  
  104.  for (i=0;i<NumAnimalTypes;i++)
  105.  OtherArray[i]->Speak(); 
  106.  
  107.  
  108.  system("pause");
  109.  return 0;
  110.  }
  111.  
  112.  
  113.  
Aug 13 '10 #7
weaknessforcats
9,208 Expert Mod 8TB
This code in the Mammal class:

Expand|Select|Wrap|Line Numbers
  1. virtual Mammal * Clone() { cout << "mammal clone called" << endl; return new Mammal(*this); }
should be:

Expand|Select|Wrap|Line Numbers
  1. virtual Mammal * Clone() { return 0; }
This make the method a hook. A hook can be overridden in a derived class but the derived class is not forced to to do this.

Suppose have the address some Mammal object in ptr:

Expand|Select|Wrap|Line Numbers
  1. Mammal* obj = ptr->Clone();
If the object pointed at by ptr is a Mammal class that did not override Mammal::Clone(), then you haven't got a clone. You have a Mammal created from the Mammal portion of the ptr object. The rest of the ptr object has been sliced off. (Research on slicing).

By having Mammal::Clone() return a 0, then if a derived class does not implement Clone() then you cannot clone objects of thise classes. The caller just verifies that the Mammal* returned after the call to Clone() is not null.
Aug 13 '10 #8
Thanks for the explanation. But I am trying to understand the code in this book that I am learning with i would like to know if I am understanding this specific code correctly.
Aug 14 '10 #9
weaknessforcats
9,208 Expert Mod 8TB
Many books have poor examples. In the case of hierarchies using virtual functions the going-in position is that:

1) you will create a derived object.
2) you will refer to the derived object using only a base class pointer
3) when you call a base class method, the call is diverted to the derived class method (if available).

Therefore, your Mammal* may not point to a Mammal. Therefore, the Clone() of Mammal returns a bad object if a) the actual object is not a Mammal and b)the actual object does not support Clone().

I understand about trying to work through your textbook but I want you to understand that in all design there is a downside. Not seeing the downside in C++ will cause you more trouble than you can imagine. Maybe what I say does not apply in this case but I guarantee that it will apply in a case you encounter later on. Maybe at that time you remember this series of posts and go "Wait a minute...".
Aug 15 '10 #10
You're absolutely right about books. I tried to contact the author of the book and his email is no longer valid. I am going to make the changes you've posted and report back. Thanks.
Aug 16 '10 #11

Sign in to post your reply or Sign up for a free account.

Similar topics

3
by: ccs | last post by:
In Meyers' book he gave an example of "virtual copy constructor", which is quite different to an "ordinary" copy constructor by: 1. it returns a pointer to an object instead of a reference. 2. it...
8
by: RonHiler | last post by:
My copy constructor is crashing my program, and I can't figure out why. I'll try to make the code listing as short as I can. Here are the two headers: class BreakthroughClass { public:...
16
by: jonathan cano | last post by:
QUESTION: In practice, lines 36 and 37 below are usually equivalent to the default copy constructor (.e.g line 33). My questions are: (a) Does ISO 14882 guarantee that lines 36 and 37 are...
4
by: Jeff Mallett | last post by:
VC++.NET gave me Compiler Error C2621, which states, "A union member cannot have a copy constructor." Yikes, that can't be true! As I understand it, *all* class objects have copy constructors,...
14
by: Arne | last post by:
In C++ we have a copy constructor. What is the equivalent in .Net? Would that be a clone method?
3
by: lhr_cool_guy | last post by:
The following code is compiling correctly on Visual Studio .NET 2003 but crashes. The problem is that the copy constructor is not being called when it should be. Am I doing something wrong or is...
3
by: Marcin Kalicinski | last post by:
Hi, Having the following program: #include <iostream> struct A { A() { std::cout << "A::A()\n"; } A(const A &) { std::cout << "A::A(const A &)\n"; }
11
by: Nindi73 | last post by:
A few days a ago I posted my code for a deep copy pointer which doesn't require the pointee object to have a virtual copy constructor. I need help with checking that it was exception safe and...
2
by: Henrik Goldman | last post by:
Hi, Lets say you have class A which holds all data types as private members. Class B then inherits from A and does *only* include a set of public functions which uses A's existing functions for...
13
by: JD | last post by:
Hi, My associate has written a copy constructor for a class. Now I need to add an operator = to the class. Is there a way to do it without change her code (copy constructor) at all? Your help...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.