1

I'm very new to C++ and would really appreciate any and all help. I have this assignment that plays around with classes and inheritance. My understanding is that I can write a virtual function in the base class that gets overridden by functions of the same name in inherited classes. When I call any of the inherited classes this works just fine, but when I plug them into a function written to take in the base class, even when the objects it receives are from inherited classes, it calls initializers from the inherited class, but other functions only from the base class. Here is a shortened version of my code:

base class:

#ifndef PLAYER_CPP
#define PLAYER_CPP
class Player 
{    
protected:
    string playerThrow;
public:
    //function that sets player throw
    void virtual setMove();
    string performMove() {return(playerThrow);}
};
#endif

inherited class:

class Avalanche: virtual public Player
{
public:
    Avalanche();    
    //set specific move for class
    void setMove() 
    {
        //always plays rock
        playerThrow = "rock";
    }
};

//initializer, inherit from player, set new name
Avalanche::Avalanche() : Player()
{   
    //initialize name string
    string newName;
    //set name
    newName = "Avalanche Player";
    //sets name in player class
    name = newName;
}

How I'm trying to use it:

class Tournament
{
public:
    Tournament();
    Player bout(Player, Player);
    Player Tournament::bout (Player p1, Player p2)
    {
        p1.setMove();
        p2.setMove();
        return p1;
    }
};

what this winds up doing is setting the move to nothing, rather than to "rock".

Thanks in advance for any pointers in the right direction. This one's got me stumped.

-Victoria

bitmask
  • 32,434
  • 14
  • 99
  • 159
quipish
  • 47
  • 2
  • 7

3 Answers3

3

You cannot use dynamic binding with copy-passed parameters. You have to pass either references (Player&) or const references (Player const&) or pointers (Player*) or pointers to const (Player const*).

Example: If you instantiate an Avalanche and pass it to something that receives a Player, this happens:

C++ sees the signature that gets a Player, so it will create a local copy of your object, using the default copy constructor with the signature: Player::Player(Player const&). This can be called with your Avalanche argument since it is inherited publicly from Player. Try hiding the copy constructor of Player, to understand what's going on.

Please feel free to point out things that were not intelligible for you.

bitmask
  • 32,434
  • 14
  • 99
  • 159
  • 1
    `Player const*` is not a const pointer, it's a pointer to a const Player. – Luchian Grigore Mar 23 '12 at 12:19
  • constness is not a detail. It's very important. – Luchian Grigore Mar 23 '12 at 12:26
  • @LuchianGrigore: The *detail* was in the language. I fully agree that constness is *not* a detail, and that a const pointer is something completely different from a pointer to const. But note the pattern: "const reference" is unambiguous because `Foo& const` simply doesn't make sense (as the const is implied, there). The same formulation means something different when talking about pointers. It was just mere lack of concentration, I guess. – bitmask Mar 23 '12 at 12:31
  • Neither is ambiguous. "The same formulation means something different when talking about pointers" not true, the position of `const` is fully defined. – Luchian Grigore Mar 23 '12 at 12:34
  • @LuchianGrigore: I believe we're talking past each other. I was talking about how it is common to talk about `Foo const&` as a "const reference". While the same language pattern, applied to pointers, not to references "const pointer" (as opposed to "pointer to const") in fact does not mean `Foo const*` but `Foo* const`. This, combined with a midday lapse of concentration, led to me write "const pointer" while I actually meant "pointer to const" :) – bitmask Mar 23 '12 at 12:41
  • I understood you perfectly. I'm sure it was just an oversight. But the correction had to be made, since mixing up concepts like this can seriously hinder a beginners learning curve. – Luchian Grigore Mar 23 '12 at 12:43
  • Thanks for the help! I've still got some bugs to iron out in my code, but it makes a lot more sense now that I see how the function makes a copy of the object passed to it rather than dealing with the original object. This makes sense, it just hadn't occurred to me before. – quipish Mar 23 '12 at 13:03
0

You're passing Player objects to bout, so you're not taking advantage of polymorphism.

You should pass pointers or by reference:

Player bout(Player*, Player*);
//or
Player bout(Player&, Player&);

Note that in your version, if you pass Avalanche objects to the method, you'll run into object slicing (look that up).

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

When you call Tournament::bout, you construct two new Player objects from the Avalanche objects that you pass in.

The Player constructor does not know about the Avalanche part of the object that it is copying/moving from, and so only copies the Player part.

p1 and p2 are Players, so they act like Players, not Avalanches.

If you don't want to construct new Player objects, then pass the arguments by reference:

Player& Tournament::bout (Player& p1, Player& p2)
{
    p1.setMove();
    p2.setMove();
    return p1;
}
Mankarse
  • 39,818
  • 11
  • 97
  • 141