1

I'm trying to do class inheritance in C++, but it obviously works very differently than in Python.

Right now, I have two classes, one called Player that is the base class, and another one called HumanPlayer that's the subclass.

The Player class is an abstract class that has two ways of working.

The first is that it acts like a singleton. It has one static function called make_move that people can call with an int and a TicTacToeGame&, and it will make a move for the player with that int as the player's number in that game of TicTacToe.

The second is that it works as a class for creating objects that have a player number as a property. So, if you construct an object with the class, you should get back an object with a player_number property. Then, if you call the make_move function with just a TicTacToeGame& on the object, it will automatically plug in its player number and use the static class method to make the move in the game.

I want the same functionality for HumanPlayer, except I just want to have to write a new static function for HumanPlayer, and that's it, since the other functionality remains the same.

Here's the code:

#include <iostream>
#include <string>
using namespace std;

class TicTacToeGame {

};

class Player {
    public:
        static void make_move(int player_number, TicTacToeGame& game);

    protected:
        int player_number;

    public:
        explicit Player(int player_number_param) {
            player_number = player_number_param;
        }

    public:
        void make_move(TicTacToeGame& game) {
            return make_move(player_number, game);
        }
};

class HumanPlayer: public Player {
    public:
        static void make_move(int player_number, TicTacToeGame& game) {}

    public:
        HumanPlayer(int player_number_param): Player(player_number_param) {}
};

int main()
{
    TicTacToeGame game;
    HumanPlayer human_player = HumanPlayer(2);
    human_player.make_move(game);
    return 0;
}

I learned recently that subclasses don't inherit constructors, so it turns out I have to write both a new static function and a constructor, which I have done. However, whenever I initialize a new HumanPlayer object, the compiler can't seem to find a match for the make_move(TicTacToeGame&) method, and I'm not sure why.

The specific error message I'm getting is

C:\Users\London\Desktop\Python Programs\LearningC++\FirstProgram_SO.cpp: In function 'int main()': C:\Users\London\Desktop\Python Programs\LearningC++\FirstProgram_SO.cpp:41:29: error: no matching function for call to 'HumanPlayer::make_move(TicTacToeGame&)' human_player.make_move(game); ^ C:\Users\London\Desktop\Python Programs\LearningC++\FirstProgram_SO.cpp:29:15: note: candidate: static void HumanPlayer::make_move(int, TicTacToeGame&) static void make_move(int player_number, TicTacToeGame& game) {} ^~~~~ C:\Users\London\Desktop\Python Programs\LearningC++\FirstProgram_SO.cpp:29:15: note: candidate expects 2 arguments, 1 provided

How can I get the HumanPlayer class to work in the same way the Player class does?

Pro Q
  • 4,391
  • 4
  • 43
  • 92
  • Also, the `Player` class compiles fine if I add in an empty definition for its static `make_move` method. I can create an object with it and do `obj.make_move(game)` and it compiles. However, with `HumanPlayer`, that doesn't seem to be the case. – Pro Q May 23 '18 at 23:44
  • 1
    Where is the int? You're supposed to pass a int as first parameter. Edit: Ah you want the parents non-static `make_move` to be called? – tkausl May 23 '18 at 23:44
  • The `HumanPlayer` should inherit the `make_move(TicTacToe&)` method from the `Player` class. The `make_move(TicTacToe&)` method then calls the static `make_move(int, TicTacToe&)` method, using the protected variable `player_number` as the `int`. – Pro Q May 23 '18 at 23:46
  • @tkausl precisely – Pro Q May 23 '18 at 23:47

1 Answers1

2

The redefinition of the static function with the same name is hiding the one you want to use.

Either rename it differently or add

public:
    using Player::make_move;

Note that unlike Java you don't need to repeat public: before every function, the same visibility applies as long as you don't change it.

class YourClass {
public:
    void foo1(); // public
    void bar1(); // also public
protected:
    void foo2(); // protected
    void bar2(); // also protected
};
O'Neil
  • 3,790
  • 4
  • 16
  • 30
  • How can I tell if a function will hide the one I want to use? I had assumed that having different parameter types would cause it to not hide. – Pro Q May 24 '18 at 00:02
  • @ProQ Overload resolution is only done after determining which class defines the name. – Barmar May 24 '18 at 00:05
  • 2
    In other words, redefining a function in a derived class replaces all overloads, not just the ones with the same parameter types. – Barmar May 24 '18 at 00:05
  • If I add `using Player::make_move;` it complains because `Player` is just an abstract class, so it doesn't have a definition for `make_move(int, TicTacToe&)`. Is there any easy way to get around this? Do I include `using Player::make_move;` *after* I define the static function in `HumanPlayer`? – Pro Q May 24 '18 at 00:23
  • 1
    @ProQ You can't leave the static function unimplemented. A class is made abstract by providing (at least one) pure virtual member functions. – O'Neil May 24 '18 at 00:35
  • Ah, so I think I'm now running into issues more along the lines of [this](https://stackoverflow.com/questions/3313754/static-abstract-methods-in-c). I'll do more research. – Pro Q May 24 '18 at 00:43
  • @ProQ No. You're looking for [Non-Virtual interface idiom](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface). – O'Neil May 24 '18 at 00:44
  • I don't see any static functions in the Non-Virtual interface idiom. How would I convert my current classes into something that uses that format? – Pro Q May 24 '18 at 00:49
  • @ProQ Turn your static function into the virtual one. – O'Neil May 24 '18 at 00:51
  • In my case, that takes away the point of there being a static version that can be called without an object being created. I think I'm better off just not using a `Player` class at all. – Pro Q May 24 '18 at 02:58