0

I have an assignment that demands I use a copy constructor. So let's say we have the following code:

class Animal   /*abstract class*/
{
private:
    string name;
    int age;
public:
    Animal();
    ~Animal();
    virtual int is_bad() = 0;
}

class Dog : public Animal
{
public:
    Dog();
    ~Dog();
    int is_bad() {
        return 0;
    }
}

/*constructors*/

Animal::Animal(int age,string name)
{
    this->age=age;
    this->name=name;
}

Dog::Dog(int age, string name) : Animal(age,name)
{
    cout << "Woof" << endl;
}

/*main*/

int main()
{
    Animal * c;

    c = new Dog(10,"rex");

    return 0;
}

So my question is as follows. If I want to make a copy constructor that makes a duplicate of dog for example Dog(const Dog & d), what do I need to add to my code and how do I call it in my main function? I'm a newbie so I'll need a quite elaborated answer.

MWiesner
  • 8,868
  • 11
  • 36
  • 70
  • 1
    What is `creature`? `Animal`? – AndyG Jan 18 '16 at 15:43
  • You have not defined `creature` in your code - did you mean `Animal`? Do you want a copy constructor that takes an existing `Dog` or an existing `Animal`? That will change how you use it from your program. – D Stanley Jan 18 '16 at 15:44
  • 1
    You need to add a `virtual` function `clone()` or `make_copy()`. Search for those functions in SO. – R Sahu Jan 18 '16 at 15:44
  • Yes,I'm sorry got confused with my assignment. It's Animal * c > – puck_this_program Jan 18 '16 at 15:45
  • 1
    Is this the code from your assignment? In real life, I would say "don't define a copy constructor, the compiler generated one is fine". Do you understand what the signature of the copy constructor should be? – Martin Bonner supports Monica Jan 18 '16 at 15:49
  • Try it. You'll find that it just works. – Pete Becker Jan 18 '16 at 15:50
  • 1
    @RSahu - the question is about copying a `Dog` object, not about cloning through a base class pointer. – Pete Becker Jan 18 '16 at 15:51
  • @PeteBecker, the OP needs to implement `clone()` as a virtual function. The implementation of `Dog::clone()` can use the copy constructor. – R Sahu Jan 18 '16 at 15:54
  • @PeteBecker: That's what I thought at first, but the sample main doesn't have a `Dog*` - just an `Animal*` – Martin Bonner supports Monica Jan 18 '16 at 15:54
  • @RSahu: Are you sure? It's not clear. The OP may just want `Dog *dog = new Dog(10, "rex");` `Dog copy = *dog;`. – Martin Bonner supports Monica Jan 18 '16 at 15:55
  • @Martin Bonner If I use the default copy constructor, just calling it in main will do it? The `age` and `name` if I 'm right are a part of `Animal`. Will this do the trick? – puck_this_program Jan 18 '16 at 15:55
  • Reopened: the question asks about implementing `Dog(const Dog & d)`. There is no cloning involved. – Pete Becker Jan 18 '16 at 15:56
  • Given everything posted so far, the default copy constructors are both exactly what you need (default copy constructor of Dog, which invokes the default copy constructor of Animal). – JSF Jan 18 '16 at 15:58
  • What I want to do is make a copy of `Dog` having an abstract class is what troubles me. Do I just ignore it or I need to implement `clone()` as said below? – puck_this_program Jan 18 '16 at 15:58
  • The default copy constructor for both `Animal` and `Dog` work perfectly. If you create a copy of a `Dog` it will work. If you copy `*c`, then you will get a copied `Animal` (not a copied `Dog`), because name and age are members of `Animal`, they will be present. If you had members that were only present in `Dog`, they wouldn't be copied. If that's not what you want, you will need a virtual `clone` function. – Martin Bonner supports Monica Jan 18 '16 at 15:58
  • Can you please show a sample of the code that you want to work. We don't really understand what you are trying to do. – Martin Bonner supports Monica Jan 18 '16 at 15:59
  • `Animal` being abstract is not an issue. 1) If the compiler defines the `Dog` copy constructor, it will correctly include the call to the `Animal` copy constructor. But if you explicitly define the `Dog` copy constructor, that needs to explicitly invoke the `Animal` copy constructor (to avoid an implied call to the `Animal` default constructor. 2) If you copy from the object pointed to be an `Animal*`, you need a cast in order to use the `Dog` copy constructor, which is why some may think you should be using a clone method instead of a direct call to a copy constructor. – JSF Jan 18 '16 at 16:03
  • @JSF `if you explicitly define the Dog copy constructor, that needs to explicitly invoke the Animal copy constructor (to avoid an implied call to the Animal default constructor` Do you have a link for that? I had been searching for exactly that all over the net and never found something that helped me out. – puck_this_program Jan 18 '16 at 16:52
  • A copy constructor looks like: `Dog(Dog const&d) : Animal(d) {}` The part right after the `:` is where you put the explicit invocation of the base class constructor, and as I just showed it would invoke the base class's copy constructor (unless the base class had some very strange overload to its constructor). If you had left that part out, you typically don't get a compiler error, just an inappropriate call to the base class default constructor. If the base class had some bizarre overload to its constructor, you might need: `Dog(Dog const&d) : Animal(static_cast(d)) {}` – JSF Jan 18 '16 at 18:45

3 Answers3

0

When you use a Animal* to point to a Dog object, you cannot use the copy constructor. You'll need to implement a clone() function.

int main()
{
    Animal * c;

    c = new Dog(10,"rex");
    Animal* newDog = c->clone();

    return 0;
}

where clone() is declared as below:

class Animal   /*abstract class*/
{
private:
    string name;
    int age;
public:
    Animal();
    ~Animal();
    virtual Animal* clone() const = 0;
    virtual int is_bad() = 0;
};

clone() can be implemented in Dog using the copy constructor.

class Dog : public Animal
{
public:
    Dog();
    ~Dog();

    virtual Dog* clone() const { return new Dog(*this); }

    int is_bad() {
        return 0;
    }
};

When you have a Dog*, you can use the copy constructor directly.

int main()
{
    Dog * c;

    c = new Dog(10,"rex");

    Dog* newDog = Dog(*c);

    return 0;
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Actually you **can** directly use the copy constructor (with the original version of `c`) `Animal* newDog = new Dog(*static_cast(c));` Depending on aspects of intended usage, the OP might be better off with a clone method. But the question has not yet made that clear. – JSF Jan 18 '16 at 16:07
  • @JSF, I wouldn't recommend using `new Dog(*static_cast(c));` even though it will work for this simple example. – R Sahu Jan 18 '16 at 16:14
  • What I wanted to make was create a duplicate of object `Dog` through a copy constructor. I thought that because class `Animal` was an abstract class and because in my assignment I have a pointer in the class as well, calling the default constructor would give me errors. However, since in every `Animal` I want their pointer value to stay the same and point at a certain object calling the default constructor works. In conclusion, I just got confused because when calling the constructor of `Dog` I had to use initialization list to assign values and thought the same applied to copy constructors. – puck_this_program Jan 18 '16 at 16:45
  • I didn't understand what you meant by *However, since in every Animal I want their pointer value to stay the same and point at a certain object calling the default constructor works.* – R Sahu Jan 18 '16 at 16:58
  • @R Sahu I thought that because I had pointers in my assignment, inside of class `Animal` I wouldn't be able to use the default constructors. Then, I realised that I want the pointers inside my class to all point at a specific object. So the fact that the default copy constructor copies only the values ( I hope I'm not wrong ) doesn't bother me. Anyway, I guess I didn't actually know how the language works and got confused. Thanks for the help. – puck_this_program Jan 18 '16 at 17:05
0

If you don't write a copy constructor, a compiler adds a default one, that copies all members of that object. In your case (assignment) I guess you should write one.

To invoke a copy constructor, you have two choice:

Dog a(10, "rex");
Dog b(a); // it's calling the copy constructor
Dog c=a; // it's still calling the copy constructor
0

What I wanted to make was create a duplicate of object Dog through a copy constructor. I thought that because class Animal was an abstract class and because in my assignment I have a pointer in the class as well, calling the default constructor would give me errors. However, since in every Animal I want their pointer value to stay the same and point at a certain object calling the default constructor works. In conclusion, I just got confused because when calling the constructor of Dog I had to use initialization list to assign values and thought the same applied to copy constructors. Thanks for all the guys helping.