0

Me and my friend are making a text based game in c++ for fun, and to learn a little more. I have been trying to use pointers to classes, but am having no luck, and some errors are occurring which make absolutely no sense to me at all, and am hoping someone can help me.

Code:

    //Map.h
    #include "Player.h"

    class Map
    {
        //Virtual functions
    };

    class StartMap : public Map
    {
        //Code
    }Start;

    class JungleMap : public Map
    {
        //Code
    }Jungle;

    class RiverMap : public Map
    {
        //Code
    }River;


    //Player.h
    #ifndef MAP_H
    #define MAP_H
    #endif

    class Player
    {
        private:
            Map *PlayerMap;
            //Other variables
        public:
            void Initialize()
            {
                //Initialize variables
                PlayerMap = &Start; //This is where the error occurs, says there's a
                                    //<error-type>*Player::PlayerMap. Tried putting
                                    //this->PlayerMap = &Start, didn't help
                                    //There's no error when I make the pointer
            }

            //Bunch of other functions
    }Player;

Okay, here's my code since I decided to add .cpp files:

    //Command.h
    class Command
    {
    private:
    string GameCommand;

    void Trim();

    public:
    Command (string command) {GameCommand = command;}
    Command () {}
    void operator = (string command) {GameCommand = command;}

    void ReadCommand();

    string Print();
    }


    //Command.cpp
    #include <iostream>
    #include <string>
    #include "Command.h"
    #include "Parameter.h"

    using namespace std;

    void Command::Trim()
        {
        int LeadingPos = 0, MidCount = 0, TrailingPos = GameCommand.length()-1, Size = 0;
        string TempCommand = "";
        while (GameCommand[LeadingPos] == ' '){LeadingPos += 1;}
        while (GameCommand[TrailingPos] == ' '){TrailingPos -= 1;}
        Size = ((TrailingPos+1)-LeadingPos);
        for (int loops = 0; loops < Size; loops++)
        {
            if (MidCount > 0 && GameCommand[LeadingPos] == ' ')
            {
                LeadingPos += 1;
            }
            else
            {
                if (GameCommand[LeadingPos] == ' ')
                {
                    MidCount += 1;
                }
                TempCommand += GameCommand[LeadingPos];
                LeadingPos += 1;
            }
        }
        GameCommand = TempCommand;
    }

    void Command::ReadCommand()
    {
        Trim();
        string Parameter;
        if (GameCommand.substr(0,3) == "go ")
        {
            Parameter = GameCommand.substr(3,string::npos);
            CommandParameter.Go(Parameter);
        }
        else if (GameCommand.substr(0,4) == "dig ")
        {
            Parameter = GameCommand.substr(4,string::npos);
            CommandParameter.Dig(Parameter);
        }
        else if (GameCommand.substr(0,4) == "eat ")
        {
            Parameter = GameCommand.substr(4,string::npos);
            CommandParameter.Eat(Parameter);
        }
        else if (GameCommand.substr(0,4) == "exit" || GameCommand.substr(0,4) == "quit")
        {
            exit(0);
        }
        else if (GameCommand.substr(0,4) == "use ")
        {
            Parameter = GameCommand.substr(4,string::npos);
            CommandParameter.Use(Parameter);
        }
        else if (GameCommand.substr(0,5) == "drop ")
        {
            Parameter = GameCommand.substr(5,string::npos);
            CommandParameter.Drop(Parameter);
        }
        else if (GameCommand.substr(0,5) == "grab " || GameCommand.substr(0,5) == "take ")
        {
            Parameter = GameCommand.substr(5,string::npos);
            CommandParameter.Pickup(Parameter);
        }
        else if (GameCommand.substr(0,5) == "help ")
        {
            Parameter = GameCommand.substr(5,string::npos);
            CommandParameter.Help(Parameter);
        }
        else if (GameCommand.substr(0,5) == "look ")
        {
            Parameter = GameCommand.substr(5,string::npos);
            CommandParameter.Look(Parameter);
        }
        else if (GameCommand.substr(0,5) == "sleep")
        {
            CommandParameter.Sleep();
        }
        else if (GameCommand.substr(0,6) == "check ")
        {
            Parameter = GameCommand.substr(6,string::npos);
            CommandParameter.Check(Parameter);
        }
        else if (GameCommand.substr(0,6) == "climb ")
        {
            Parameter = GameCommand.substr(6,string::npos);
            CommandParameter.Climb(Parameter);
        }
        else if (GameCommand.substr(0,6) == "throw ")
        {
            Parameter = GameCommand.substr(6,string::npos);
            CommandParameter.Throw(Parameter);
        }
        else if (GameCommand.substr(0,7) == "attack ")
        {
            Parameter = GameCommand.substr(7,string::npos);
            CommandParameter.Attack(Parameter);
        }
        else if (GameCommand.substr(0,7) == "search ")
        {
            Parameter = GameCommand.substr(7,string::npos);
            CommandParameter.Search(Parameter);
        }
        else
        {
            cout << "Not a valid command.\n";
        }
    }

    string Print()
    {
        return GameCommand;
    }

The string GameCommand is what's not working.

Shadow
  • 3,926
  • 5
  • 20
  • 41

3 Answers3

0
class StartMap : public Map;

is syntactically incorrect. You need

class StartMap : public Map
{
   // Details of class
} Start;

You need to make similar changes to JungleMap and RiverMap.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Although legal, this is extremely bad style. The class definition should be separate to instantiation of objects of that class. – M.M Apr 12 '14 at 06:36
  • Nor is it even legal for `Player`, which is both a type and a variable name in the presented code. – WhozCraig Apr 12 '14 at 06:38
0

First thing I noticed was the semi-colon after each inheritance declaration.. class XXXXX : public Map; <-- that semi-colon shouldn't be there..

In the initialize function, I'm fairly certain you mean PlayerMap = new StartMap();

You'll need a destructor to delete it and a copy, move constructor as well as an assignment operator in order to assign, move or copy the class.

You can follow this to make the class conform to RAII: What is the copy-and-swap idiom?

Community
  • 1
  • 1
Brandon
  • 22,723
  • 11
  • 93
  • 186
  • changing `PlayerMap = &Start;` to `PlayerMap = new StartMap();` still gives the error – Shadow Apr 12 '14 at 06:32
  • The reason you get that is because you keep putting these types after the classes.. It should be `class Player {....};` not `class Player{...} Player;` Because you did this, you have an instance of Player called Player, as well as a class called Player. – Brandon Apr 12 '14 at 06:39
0

There are lots of problems with your code layout.

This doesn't do anything:

//Player.h
#ifndef MAP_H
#define MAP_H
#endif

I guess you are trying to do an include guard. The proper layout is:

#ifndef PLAYER_H
#define PLAYER_H

// all your code for the header file goes here
class Player 
{ 
// ....
};

#endif    // no more code after this line

The next issue is that Player.h should include Map.h, not the other way around. Imagine you are the compiler. You are processing Player.h. You get down as far as Map *PlayerMap; . But you don't know what Map is because you haven't seen Map.h yet. So you have to give an error and stop compiling.

The map definitions in Map.h should look like:

class StartMap : public Map
{
    //Code
};

The Start; you had on the end is poor style. It would cause undefined behaviour if two different .cpp files included Map.h because there would be two different global variables with the same name.

Moving onto the void Map::Initialize() function. You're supposed to use the constructor for initialization. Either way, my suggestion is that you don't implement this in Player.h. Instead, just have void Initialize();, and then in Map.cpp you could have:

// the global variables
StartMap start_map;
JungleMap jungle_map;

void Map::Initialize()
{
    player_map = &start_map;
}

It's a good idea to use a different naming convention for classes than for variables. So that when someone sees StartMap for example, they know immediately whether it is a class name or a variable name.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I put the `#endif` at the end of the header file like you said. Map.h has to `#include "Player.h"` because the Map class handles moving the player, by calling function contained within Player. What I'm trying to achieve is instead of nesting if's for the command that's input, to just go `Player::PlayerMap->GoSouth()` – Shadow Apr 12 '14 at 07:05
  • Otherwise it's `if (Player.GetMap() == "start") {Start.GoSouth();}` with 4 if's for each map (N,S,E,W), and there will be alot of maps. – Shadow Apr 12 '14 at 07:06
  • "the Map class handles moving the player, by calling function contained within Player. " - put that code in `Map.cpp`. `Map.cpp` can include `Player.h`', but `Map.h` shouldn't. – M.M Apr 12 '14 at 07:06
  • I don't have a Map.cpp, I've only ever had Main.cpp and used header files for everything else. I'm worried about adding other cpp files this far in in case it breaks something. (I've had to juggle all the #includes so that the header files don't include recursively.) – Shadow Apr 12 '14 at 07:20
  • Put that stuff in `main.cpp` then. Try and avoid having any executable code in header files. – M.M Apr 12 '14 at 07:28
  • If I put everything in Main.cpp, every class will have access to every other class, right? Also, it's sort of a last resort putting everything in Main.cpp, because there is a lot of code, and there'd be a lot of scrolling to fix bugs. That is why I have the header files in the first place – Shadow Apr 12 '14 at 08:25
  • You aren't making any sense. The code goes in .cpp files, not .h files. If there is too much scrolling then add more .cpp files. – M.M Apr 12 '14 at 08:54
  • class access rights are controlled by `public:`, `private:` etc. – M.M Apr 12 '14 at 08:54
  • So I decided to make .cpp files and stick the code in there, leave the other stuff in header files. I'm starting with one header file for now, and getting so many errors. Stuff like `Error: identifier "MyFunction" is undefined` and the same error but with variables like strings. The function is public and the variable private in the .h file. But get this, the error for the variable is only appearing for the first if, out of 15 (using else if). – Shadow Apr 12 '14 at 10:41
  • I fixed the undefined function error by making it static in the header file, but making the string static didn't fix the string being undefined in the .cpp file. I also made the string public, still no luck. – Shadow Apr 12 '14 at 11:10
  • making things static is probably not a good idea. Check that you took all my suggestions on board and then post your new code (maybe in a new question if it's radically different to the original). – M.M Apr 12 '14 at 12:04
  • When you get an error "identifier X is undefined", find where the declaration of X was, and make sure it is visible from that piece of code. Usually the header contains the declarations, and the cpp file includes the header. – M.M Apr 12 '14 at 12:08
  • The identifier was defined though, especially in the case of the string. In the if/else if/else block, it was only unidentified in the first if, in the else if's it worked fine. – Shadow Apr 12 '14 at 12:21
  • Which line gives the error what what is the error message? If it is the fourth to last line, `string Print()`, that should be `string Command::Print()`. – M.M Apr 12 '14 at 12:39
  • Upon changing `string Print()` in Command.cpp to `string Command::Print()` I get another error on the `Command::Print()` which is: `Error: declaration is incompatible with Command::Print() (declared at line 15 of Command.h)` also, I get heaps of error messages for seemingly unknown reasons on the file Parameter.h, which has not been edited at all, just from adding the Command.cpp file. On Parameter.h: `Error: Left of .length must have class/struct/union` – Shadow Apr 12 '14 at 12:47
  • You have to say which line of code causes each error. You haven't shown the code for Parameter.h either. The last message is pretty self-explanatory, you wrote `.length` after something that was not of class type. – M.M Apr 12 '14 at 12:53
  • But it is of a class type. And it was working fine right until I cut paste the function definitions from Command.h into Command.cpp it's the Command.cpp which is messing up every other file in the program, as well as not working itself – Shadow Apr 12 '14 at 13:00
  • Look, you have to actually show the code that has the problem, and post the error messages including which line generates each error message. I don't have a crystal ball, and your attempts to describe your code in English instead of C++ don't make any sense. It's impossible for Command.cpp to "mess up every other file in the program", and you shouldn't be cut pasting anything from Command.h into Command.cpp . – M.M Apr 12 '14 at 13:03
  • There are no errors in the code, the compiler is lying to me and throwing errors at everything. It's fixed as soon as I remove the Command.cpp file, and put the function definitions back into Command.h – Shadow Apr 12 '14 at 13:12
  • OK, signing off this thread since you have no errors and no code to post. – M.M Apr 12 '14 at 13:14
  • yeah fine, going to bed anyway, source files are silly and just break code for no reason – Shadow Apr 12 '14 at 13:16