Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

is there a generic pointer that can refer to any object?

Status
Not open for further replies.

titanzero

Programmer
May 3, 2007
30
EU
Hello All,

I am working on a project, a Tic-Tac-Toe game. I have written objects to represent 3 different players, a human player and two different computer AI players.

I want to be able, at run-time, to select which of these three player types are playing. Ideally I would want two pointers called player1 and player2 and then create 2 players from the three types (human and two AIs) and then point them to the player1 and player2 pointers. This would mean my game loop could switch between players using the pointers player1 and player2.

So my question is can c++ do this? Can I set up a generic pointer that I can assign to any object? I know it can be done with the basic data types (int, char etc.) but I can't figure out how to use a void pointer for objects.

Andy help would be much appreciated.

Thank you for your time
Andrew
 
If you just declare
Code:
class Object
{
};
and base everything else on it, then you have a generic object.
 
titanzero said:
Brilliant idea!
I wouldn't call it brilliant. A better idea is to actually model your hierarchy based on good design principles (and a Tic-Tac-Toe game is a great place to practice).

In this case, I might have a Player base class (make sure to give it a virtual destructor). This class describes the interface of what a generic player can do. Then I might have a derived class call HumanPlayer and one called ComputerPlayer (or AIPlayer or whatever). If you have multiple different AI strategies, you can derive different classes from your ComputerPlayer class. (Although if you get more advanced you might handle it a different way with something called the strategy pattern.)

Inside the derived classes, you can implement the code that is different for each of them. For example, maybe your Player class has a virtual function called GetNextMove that takes the game board information as a parameter. Your HumanPlayer can implement that function by displaying the board and asking for user input. But your ComputerPlayer classes can implement that function by looking at the current state of the board and using their different algorithms to pick the next choice.

Inside the main code, you would have two Player pointers. Then, depending on who is playing who, you use new to allocate two instances of the derived classes based on which players you want to have play (HumanPlayer, ComputerPlayer1 or ComputerPlayer2). You can assign the results to your two Player pointers and the rest of the code should be the same regardless of what types are really being used behind the Player pointers.

That's the point of polymorphism. Just creating a generic Object class doesn't help because then you can't call virtual functions on that object and you have to figure out each time you want to use the pointer what the real type it holds is. Doing it the way I described above lets you write the rest of the code once and it should work no matter how many new player types you create.
 
Thanks uolj.

That really helped and thats kind of what I did in the end. I did not make a generic object but a generic Tic-Tac-Toe player and then derived from that. Thats what I thought xwb meant.

I did not use virtual a destructor though. I shall amend this as I believe the reason is without there being a virtual function in the base object the function within the derived object can not be called. Is that correct?

Anyway I am thankful to the two of you for your time.

Andrew


 
First, sorry if I sounded rude with the "brilliant" comment. I was just trying to be silly.

As for the virtual destructor, here's an example of what I'm talking about:

Code:
int main()
{
    Player* playerOne = 0;
    Player* playerTwo = 0;

    int playerType;
    std::cin >> playerType;
    if (playerType == 1)
        playerOne = new PlayerBotA;
    else if (playerType == 2)
        playerOne = new PlayerBotB;
    else
        playerOne = new PlayerHuman;

    std::cin >> playerType;
    if (playerType == 1)
        playerTwo = new PlayerBotA;
    else if (playerType == 2)
        playerTwo = new PlayerBotB;
    else
        playerTwo = new PlayerHuman;

    Gameboard game;
    while (!game.GameOver())
    {
        playerOne->MakeMove(game);
        if (!game.GameOver())
            playerTwo->MakeMove(game);
    }

    [b][COLOR=red]delete playerOne[/color][/b];
    [b][COLOR=red]delete playerTwo[/color][/b];
}

Now, when you delete the players at the end, the destructor is called. At that point, the compiler only knows that they are Players. It doesn't know if they are PlayerHuman, PlayerBotA or PlayerBotB. So it calls the destructor for Player.

If the destructor is virtual, it knows to also destroy the derived class as well. If it isn't, then you get undefined behavior, which in some cases just means the derived destructor isn't called. So basically you're right about why you need a function to be virtual, although the destructor is a special case because it actually creates an undefined program if you don't do it.

One last thing, note the MakeMove function in my code example above. That should be virtual, too, for the same reason. You make it virtual in the Player base class so it can be called from the Player pointer, and you implement it differently in each derived class that uses different techniques for making a move.

Hope that helps!

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top