I'm getting an error "invalid use of incomplete type 'class map'

C++

C++ Problem Overview


I am making a basic text based RPG sorry if my question is stupid because im new to c++. So basically I have a small combat class that i have to link back and forth to from the map class so I had to forward declare my map class and it comes up with the error. BTW sorry there aren't any comments.

Here is the error: invalid use of incomplete type class Map

#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class Map;
class Player
{
public:
    int health;
    int damage;
    int defense;
    int gems=0;
    string race;
    string name;
    string location;


};
class Enemy
{
    public:

    int ehealth;
    int edamage;
    int edefense;
    int echoice;

};
class combat
{
public:
    Map* mapobj;
    int damagedealt;
    Player playerobj;
    Enemy enemeyobj;
    string cchoice;
    string retry;

    void initial()
    {
        cout <<"A wild orc has appeared\n";
        cout <<"What do you do?\n";
        cout <<"---------------------------\n";
        cout <<"|-------------------------|\n";
        cout <<"|----Attack-----Defend----|\n";
        cout <<"|-------------------------|\n";
        cout <<"---------------------------\n";
        cin >>cchoice;
        this->battle();
    }
    void newturn()
    {
        cout <<"The orc is still alive!";
        cout <<"What do you do?";
        cout <<"\n---------------------------\n";
        cout <<"|-------------------------|\n";
        cout <<"|----Attack-----Defend----|\n";
        cout <<"|-------------------------|\n";
        cout <<"---------------------------\n";
        cin >>cchoice;
        this->battle();
    };
    void battle()
    {

        enemeyobj.echoice = rand() % 2;
        if (enemeyobj.echoice= 1)
        {
            if (cchoice=="Attack")
            {
            playerobj.damage;
            enemeyobj.ehealth=enemeyobj.ehealth-playerobj.damage;
            cout <<"You did "<<playerobj.damage<<" points of damge to the enemey.\n";
            if (enemeyobj.ehealth>0)
            {
                playerobj.health=enemeyobj.edamage-playerobj.health;
                cout <<"The enemyattacked you. You now have "<<playerobj.health<<" health";
                if (playerobj.health>0)
                {
                    this->newturn();
                }
                else if (playerobj.health<=0)
                {
                    cout <<playerobj.name<<"was killed\n";
                    cout <<"Game Over";

                }

            }
            else if (enemeyobj.ehealth<=0)
            {
                    cout <<"You have defeated the orc!";
                    if (playerobj.location=="a")
                    {
                        mapobj->relaypointa();
                    }

            }

            }
            else if (cchoice=="Defend")
            {
                damagedealt=enemeyobj.edamage-playerobj.defense;
                playerobj.health=damagedealt-playerobj.health;
                cout <<"You defend but the enemey was able to deal\n";
                cout <<damagedealt<<" points of damage your health is\n";
                cout <<playerobj.health;
                if (playerobj.health>0)
                {
                    this->newturn();
                }
                else if (playerobj.health<=0)
                {
                    cout <<playerobj.name<<"was killed\n";
                    cout <<"Game Over";
                }
            }
        }
        else if (enemeyobj.echoice=2)
        {
            if (cchoice=="Attack")
            {
             damagedealt=enemeyobj.edefense-playerobj.damage;
             enemeyobj.ehealth=enemeyobj.ehealth-damagedealt;
             cout <<"You did "<<damagedealt<<" points of damage to the enemey";
             if (enemeyobj.ehealth>0)
             {
                 this->newturn();
             }
             else if (enemeyobj.ehealth<=0)
             {
                 cout <<"You have defeated the orc!";
                 mapobj->relaypointa();
             }
            }
            else if (cchoice=="Defend")
            {
                cout <<"Both parties defended";
                this->newturn();
            }
        }
    }
    };





class Map
{
    public:
    combat combatobj;
    string mchoice;
    int espawn;
    Player playerobj;
    Enemy enemeyobj;
    void relaypointaespawn()
    {
    playerobj.location=="relaypointa";
    enemeyobj.ehealth = rand() % 50 + 100;
    enemeyobj.edamage = rand() % 50 + 75;
    enemeyobj.edefense = rand() % 50 + 50;
    combatobj.initial();
    }
    void relaypointa()
    {
        cout <<"You have found yourself at the\n";
        cout <<"mouth of a mighty river to the north\n";
        cout <<"What do you want to do?\n";


    }


    void relaypointb()
    {
    playerobj.location=="relaypointb";
    cout << "\n\n%%%%%%%%%%%%%%%%%%%%\n";
    cout << "%                  %\n";
    cout << "%   #Wild North#   %\n";
    cout << "%                  %\n";
    cout << "%%%%%%%%%%%%%%%%%%%%\n\n";
    cout <<"You have entered the wild north this is where your journey starts\n";
    cout <<"What would you like to do\n\n";
    cin >>mchoice;
    if (mchoice=="Travel")
    {
        cout <<"Where would you like to travel?\n";
        cin >>mchoice;
        if (mchoice=="North")
        {

        }
        else if (mchoice=="East")
        {

        }
        else if (mchoice=="South")
        {

        }
        else if (mchoice=="West")
        {
            this->relaypointaespawn();
        }
        else
        {
            cout <<"Invalid command\n\n";
            this->relaypointb();
        }
           }


    }
    void relaypointcespawn()
    {
        playerobj.location=="a";
        enemeyobj.ehealth = rand() % 50 + 100;
        enemeyobj.edamage = rand() % 50 + 75;
        enemeyobj.edefense = rand() % 50 + 50;
        espawn = rand() % 2;
    }
};

C++ Solutions


Solution 1 - C++

Your first usage of Map is inside a function in the combat class. That happens before Map is defined, hence the error.

A forward declaration only says that a particular class will be defined later, so it's ok to reference it or have pointers to objects, etc. However a forward declaration does not say what members a class has, so as far as the compiler is concerned you can't use any of them until Map is fully declared.

The solution is to follow the C++ pattern of the class declaration in a .h file and the function bodies in a .cpp. That way all the declarations appear before the first definitions, and the compiler knows what it's working with.

Solution 2 - C++

I am just providing another case where you can get this error message. The solution will be the same as Adam has mentioned above. This is from a real code and I renamed the class name.

class FooReader {
  public:
     /** Constructor */
     FooReader() : d(new FooReaderPrivate(this)) { }  // will not compile here
     .......
  private:
     FooReaderPrivate* d;
};

====== In a separate file =====
class FooReaderPrivate {
  public:
     FooReaderPrivate(FooReader*) : parent(p) { }
  private:
     FooReader* parent;
};

The above will not pass the compiler and get error: invalid use of incomplete type FooReaderPrivate. You basically have to put the inline portion into the *.cpp implementation file. This is OK. What I am trying to say here is that you may have a design issue. Cross reference of two classes may be necessary some cases, but I would say it is better to avoid them at the start of the design. I would be wrong, but please comment then I will update my posting.

Solution 3 - C++

This is because you need to show the at least decleration of the functions.

For workaround, create interface class with pure virtual methods for map class. Declare the functions that you are using ( as I see only relaypointa) then put this interface class in the beginning of the file and ofcourse do not forget to derive the map from it and use pointer to interface. combat class will see the interface and pure virtual function, so it will be okay.

I see this problem when I want to use single page online compiler

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;
class MapIf {
    public:
        virtual void relaypointa() = 0;
};
class Player {
    public:
        int health;
    int damage;
    int defense;
    int gems = 0;
    string race;
    string name;
    string location;

};
class Enemy {
    public:

        int ehealth;
    int edamage;
    int edefense;
    int echoice;

};
class combat {
    public:
        MapIf * mapobj;
    int damagedealt;
    Player playerobj;
    Enemy enemeyobj;
    string cchoice;
    string retry;

    void initial() {
        cout << "A wild orc has appeared\n";
        cout << "What do you do?\n";
        cout << "---------------------------\n";
        cout << "|-------------------------|\n";
        cout << "|----Attack-----Defend----|\n";
        cout << "|-------------------------|\n";
        cout << "---------------------------\n";
        cin >> cchoice;
        this -> battle();
    }
    void newturn() {
        cout << "The orc is still alive!";
        cout << "What do you do?";
        cout << "\n---------------------------\n";
        cout << "|-------------------------|\n";
        cout << "|----Attack-----Defend----|\n";
        cout << "|-------------------------|\n";
        cout << "---------------------------\n";
        cin >> cchoice;
        this -> battle();
    };
    void battle() {

        enemeyobj.echoice = rand() % 2;
        if (enemeyobj.echoice = 1) {
            if (cchoice == "Attack") {
                playerobj.damage;
                enemeyobj.ehealth = enemeyobj.ehealth - playerobj.damage;
                cout << "You did " << playerobj.damage << " points of damge to the enemey.\n";
                if (enemeyobj.ehealth > 0) {
                    playerobj.health = enemeyobj.edamage - playerobj.health;
                    cout << "The enemyattacked you. You now have " << playerobj.health << " health";
                    if (playerobj.health > 0) {
                        this -> newturn();
                    } else if (playerobj.health <= 0) {
                        cout << playerobj.name << "was killed\n";
                        cout << "Game Over";

                    }

                } else if (enemeyobj.ehealth <= 0) {
                    cout << "You have defeated the orc!";
                    if (playerobj.location == "a") {
                        mapobj -> relaypointa();
                    }

                }

            } else if (cchoice == "Defend") {
                damagedealt = enemeyobj.edamage - playerobj.defense;
                playerobj.health = damagedealt - playerobj.health;
                cout << "You defend but the enemey was able to deal\n";
                cout << damagedealt << " points of damage your health is\n";
                cout << playerobj.health;
                if (playerobj.health > 0) {
                    this -> newturn();
                } else if (playerobj.health <= 0) {
                    cout << playerobj.name << "was killed\n";
                    cout << "Game Over";
                }
            }
        } else if (enemeyobj.echoice = 2) {
            if (cchoice == "Attack") {
                damagedealt = enemeyobj.edefense - playerobj.damage;
                enemeyobj.ehealth = enemeyobj.ehealth - damagedealt;
                cout << "You did " << damagedealt << " points of damage to the enemey";
                if (enemeyobj.ehealth > 0) {
                    this -> newturn();
                } else if (enemeyobj.ehealth <= 0) {
                    cout << "You have defeated the orc!";
                    mapobj -> relaypointa();
                }
            } else if (cchoice == "Defend") {
                cout << "Both parties defended";
                this -> newturn();
            }
        }
    }
};

class Map: public MapIf {
    public: combat combatobj;
    string mchoice;
    int espawn;
    Player playerobj;
    Enemy enemeyobj;
    void relaypointaespawn() {
        playerobj.location == "relaypointa";
        enemeyobj.ehealth = rand() % 50 + 100;
        enemeyobj.edamage = rand() % 50 + 75;
        enemeyobj.edefense = rand() % 50 + 50;
        combatobj.initial();
    }
    void relaypointa() {
        cout << "You have found yourself at the\n";
        cout << "mouth of a mighty river to the north\n";
        cout << "What do you want to do?\n";

    }

    void relaypointb() {
        playerobj.location == "relaypointb";
        cout << "\n\n%%%%%%%%%%%%%%%%%%%%\n";
        cout << "%                  %\n";
        cout << "%   #Wild North#   %\n";
        cout << "%                  %\n";
        cout << "%%%%%%%%%%%%%%%%%%%%\n\n";
        cout << "You have entered the wild north this is where your journey starts\n";
        cout << "What would you like to do\n\n";
        cin >> mchoice;
        if (mchoice == "Travel") {
            cout << "Where would you like to travel?\n";
            cin >> mchoice;
            if (mchoice == "North") {

            } else if (mchoice == "East") {

            } else if (mchoice == "South") {

            } else if (mchoice == "West") {
                this -> relaypointaespawn();
            } else {
                cout << "Invalid command\n\n";
                this -> relaypointb();
            }
        }

    }
    void relaypointcespawn() {
        playerobj.location == "a";
        enemeyobj.ehealth = rand() % 50 + 100;
        enemeyobj.edamage = rand() % 50 + 75;
        enemeyobj.edefense = rand() % 50 + 50;
        espawn = rand() % 2;
    }
};

int main() {

}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser2998425View Question on Stackoverflow
Solution 1 - C++AdamView Answer on Stackoverflow
Solution 2 - C++Kemin ZhouView Answer on Stackoverflow
Solution 3 - C++user2908225View Answer on Stackoverflow