2

How do you copy a derived class to another?

I'm terminologically deficient, so I'll try to illustrate with an example.

We are playing a card game with a computer player and human player. Card and Command are other classes.

class Player
{
    Card *Hand[4];
    // etc...
};

class Human: public Player
{
    Command getCommand();
    void PlayCard(Card card);
    void quit();
    // etc...
};

class Computer: public Player
{
    Command ai();
    void PlayCard(Card card);
    // etc...
};

And somewhere in the main function we have ...

// ...
Human p1; // Assume initialized and usable.
if(p1.getCommand() == QUIT)
{
    cout << "PLAYER 1 RAGEQUITS WHAT A NOOB LOL << endl;
    cout << "A COMPUTER WILL NOW TAKE OVER." << endl;
    p1.quit()
    p1 = new Computer(); // THE IDEA BEING THAT WE WANT TO PRESERVE p1's MEMBERS.
}
// ...

What I am trying to do is converting p1 to a "Computer" while preserving the state of its members.

Do we use a copy constructor to do this? If not, what methods do you use?

EDIT: Is this the way to use the assignment operator?

Computer& Human::operator=(const Human &h) // Assignment operator
{
    Hand = h.Hand;
    member2 = h.member2;
    member3 = h.member3;
    ...

    return *this;
}

Do we need to delete/free anything in the main?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
cozos
  • 787
  • 10
  • 19

4 Answers4

5

You have a design problem here. If you want to switch a player from a Human to a Computer while maintaining the common member variables then you should structure your classes in that way.

class Player
{ 
public:
    friend class Human;    // These friends are necessary if the controllers
    friend class Computer; // need access to Player's private data.

    Card hand[4];
    Controller* controller;
};

class Controller
{
public:
    virtual Command getCommand(Player const&) = 0;
};

class Human : public Controller
{
public:
    Command getCommand(Player const&) { /* get command from user input */ }
};

class Computer : public Controller
{
public:
    Command getCommand(Player const&) { /* get command from AI */ }
};

Then, when you need to switch from Human to Computer, just change the controller.

p1->controller = new Computer();

This way, the cards will be maintained, only the control mechanism will be changed.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
2

You could use a constructor. For this particular case I'd probably have a method called something like "CopyGameState".

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
2

Copy constructor is used to copy an existing object a new instance of the same class.

What you need is an assignment operator (operator=), which allows assigning the value of a different type to your existing class object.

littleadv
  • 20,100
  • 2
  • 36
  • 50
  • This is completely backwards, since it won't replace the vtable. – Ben Voigt Jul 21 '11 at 23:00
  • @Ben - you can't replace vtable of a constructed class. – littleadv Jul 21 '11 at 23:12
  • Not without creating a new object... which is why the assignment operator isn't a good solution here. He needs a new object, with a new vtable. – Ben Voigt Jul 21 '11 at 23:15
  • @Ben - he needs a redesign. I didn't clearly understand what the *real* problem is until after I read Peter's answer. – littleadv Jul 21 '11 at 23:17
  • He wants `p1->PlayCard()` to start using `Computer::PlayCard` instead of `Human::PlayCard`, while keeping the member data intact. Either @Peter's answer or mine will get him there. – Ben Voigt Jul 21 '11 at 23:18
2

It wouldn't be a copy constructor, but a converting constructor. Something like:

Computer::Computer(const Player& had_to_go) : Player(had_to_go) {}

This will use Player's copy constructor to preserve the members in the common base class.

Of course, you'd better make Player::Player(const Player&) work right, following the "rule of three" and all.

In the end, you'd do something like:

p1.quit();
Computer* replacement = new Computer(p1);
delete p1;
p1 = replacement;
Community
  • 1
  • 1
Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Can you explain to me what the "rule of three" is :P, also, is Player::Player(const Player&) Player's copy constuctor? – cozos Jul 21 '11 at 23:07
  • @Ir Win: Yes, it's `Player`'s copy constructor, and the rule of three says that if you have a custom copy constructor, assignment operator, or destructor, you need all three. In this case, it's because of the `Card*` stored in `Player`. The compiler-provided copy will copy the pointer, which means you'll eventually delete it twice. Not good. There's a very good explanation in the C++-FAQ tag. I'll add a link to it from my answer. – Ben Voigt Jul 21 '11 at 23:14