Undefined Reference to Class::Function

Hello fellow programmers. I'm making a simple tile-based RPG and I've run into a bit of trouble when I put my code into classes. Im fairly new to classes since I seldom make projects this big, but I cant figure out what I've done wrong, and I've tried googling it and the previous threads were no help.

Heres my main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <iostream>
#include "windows.h"
#include "math.h"
#include "time.h"
#include <string>
#include "Goblin.h"
#include "User.h"
#include "Inventory.h"
#include "Maps.h"

using namespace std;

void treasureGet();

Goblin goblinObject;
User userObject;
Inventory Io;
Maps MO;

int counter = 0;

bool gotten[20]{0};
int gottenCounter = 0;

bool game_running = true;

int main()
{

    while(game_running == true){
        //SCREEN CLEARING
        system("cls");


        for(int display = 0; display < 22; display++){
            cout << MO.map[MO.currentMap][display] <<  endl;
        }

        //MAIN DISPLAYED INFORMATION
        cout << "Money:$" << userObject.points << endl;
        cout << "F1:Inventory" << endl;
        cout << "Health:" << userObject.health << endl;
        //PAUSE BEFORE ACTION
        system("pause>nul");

        //ARROW KEY ACTIONS
        if(GetAsyncKeyState(VK_DOWN)){
            if(MO.map[MO.currentMap][MO.y + 1][MO.x] != '#' && MO.map[MO.currentMap][MO.y + 1][MO.x] != 'D' && MO.map[MO.currentMap][MO.y + 1][MO.x] != 'G'){
                MO.map[MO.currentMap][MO.y][MO.x] = ' ';
                MO.y++;
                MO.map[MO.currentMap][MO.y][MO.x] = '@';
            }
            else if(MO.map[MO.currentMap][MO.y + 1][MO.x] == 'G'){
                goblinObject.gx = MO.x;
                goblinObject.gy = MO.y + 1;
                goblinObject.goblinBattle();
            userObject.lastKeyPressed = 1;
            }
        }
        if(GetAsyncKeyState(VK_UP)){
            if(MO.map[MO.currentMap][MO.y - 1][MO.x] != '#' && MO.map[MO.currentMap][MO.y - 1][MO.x] != 'D' && MO.map[MO.currentMap][MO.y - 1][MO.x] != 'G'){
                MO.map[MO.currentMap][MO.y][MO.x] = ' ';
                MO.y--;
                MO.map[MO.currentMap][MO.y][MO.x] = '@';
            }
            else if(MO.map[MO.currentMap][MO.y - 1][MO.x] == 'G'){
                goblinObject.gx = MO.x;
                goblinObject.gy = MO.y - 1;
                goblinObject.goblinBattle();
            userObject.lastKeyPressed = 1;
            }
        }
        if(GetAsyncKeyState(VK_RIGHT)){
            if(MO.map[MO.currentMap][MO.y][MO.x + 1] != '#' && MO.map[MO.currentMap][MO.y][MO.x + 1] != 'D' && MO.map[MO.currentMap][MO.y][MO.x + 1] != 'G'){
                MO.map[MO.currentMap][MO.y][MO.x] = ' ';
                MO.x++;
                MO.map[MO.currentMap][MO.y][MO.x] = '@';
            }
            else if(MO.map[MO.currentMap][MO.y][MO.x + 1] == 'G'){
                goblinObject.gx = MO.x + 1;
                goblinObject.gy = MO.y;
                goblinObject.goblinBattle();
            userObject.lastKeyPressed = 3;
            }
        }
        if(GetAsyncKeyState(VK_LEFT)){
            if(MO.map[MO.currentMap][MO.y][MO.x - 1] != '#' && MO.map[MO.currentMap][MO.y][MO.x - 1] != 'D' && MO.map[MO.currentMap][MO.y][MO.x - 1] != 'G'){
                MO.map[MO.currentMap][MO.y][MO.x] = ' ';
                MO.x--;
                MO.map[MO.currentMap][MO.y][MO.x] = '@';
            }
            else if(MO.map[MO.currentMap][MO.y][MO.x - 1] == 'G'){
                goblinObject.gx = MO.x - 1;
                goblinObject.gy = MO.y;
                goblinObject.goblinBattle();
                userObject.lastKeyPressed = 4;
            }
        }
        if(GetAsyncKeyState(VK_F1)){
            Io.inventoryOpen();
        }

        if(counter == 9 && userObject.health < 20){
            counter = 0;
            userObject.health++;
        }
        else if(counter < 9){
            counter++;
        }

    }
    return 0;
}


Goblin.cpp (made for a mob in the game)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
#include <iostream>
#include "windows.h"
#include "math.h"
#include "time.h"
#include <string>
#include "Goblin.h"
#include "User.h"
#include "Inventory.h"
#include "Maps.h"

using namespace std;

Goblin::Goblin()
{
    //ctor
}

Goblin go;
User uo;
Inventory io;
Maps mo;

//GOBLIN BATTLE FUNCTION
Goblin::goblinBattle(){
    srand(time(0));
    go.battle = true;
    system("cls");
    while(go.battle == true){
        if(go.goblinHealth > 0){
            cout << "Health:" << uo.health << endl;
            cout << "Goblin's Health:" << go.goblinHealth << endl;
            cout << "1:Attack\n";
            cout << "2:Inventory\n";
            cout << "3:Run!\n";
            cin >> uo.userInput;
            system("cls");
            if(uo.userInput == 1){
                go.currenta = rand() % uo.attackRating;
                go.currentb = rand() % 3;
                go.goblinHealth = go.goblinHealth - go.currenta;
                uo.health = uo.health - go.currentb;
                cout << "You hit for " << go.currenta << " damage." << endl;
                cout << "The goblin hit for " << go.currentb << " damage." << endl;
            }
            else if(uo.userInput == 2){
                io.inventoryOpen();
            }
            else if(uo.userInput == 3){
                io.chance[8] = rand() % 100;
                if(io.chance[8] < 50){
                go.battle = false;
                }
                else{
                cout << "You failed to run away!" << endl;
                go.currentb = rand() % 3;
                uo.health = uo.health - go.currentb;
                cout << "The goblin hit for " << go.currentb << " damage." << endl;
                }
            }
        }
        else{
            io.chance[0] = rand() % 100;
            io.chance[1] = rand() % 100;
            io.chance[2] = rand() % 100;
            io.chance[3] = rand() % 100;
            if(io.chance[0] < 30){
                io.inv[io.currentInv + 1] = io.itemNames[1];
                cout << "You got an " << io.itemNames[1] << endl;
                io.chance[0] = 1000;
            }
            if(io.chance[1] < 30){
                io.inv[io.currentInv + 1] = io.itemNames[3];
                cout << "You got an " << io.itemNames[3] << endl;
                io.chance[1] = 1000;
            }
            if(io.chance[2] < 10){
                io.inv[io.currentInv + 1] = io.itemNames[2];
                cout << "You got a " << io.itemNames[2] << endl;
                io.chance[2] = 1000;
                }
            if(io.chance[3] < 10){
                io.inv[io.currentInv + 1] = io.itemNames[4];
                cout << "You got a " << io.itemNames[4] << endl;
                io.chance[3] = 1000;
            }
            system("pause");
            go.battle = false;

            }
        }
    go.goblinHealth = 10;
    mo.map[mo.currentMap][go.gy][go.gx]= ' ';
}

Goblin.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#ifndef GOBLIN_H
#define GOBLIN_H

#include <iostream>
#include "windows.h"
#include "math.h"
#include "time.h"
#include <string>
#include "Goblin.h"
#include "User.h"
#include "Inventory.h"
#include "Maps.h"

using namespace std;

class Goblin
{
    public:
        Goblin();
        void goblinBattle();
        int goblinHealth = 10;
        int goblinCounter = 0;
        int battleHappened = 0;
        int currenta = 0;
        int currentb = 0;
        int gx;
        int gy;
        bool battle = false;
    protected:
    private:
};

#endif // GOBLIN_H 


My other 3 classes have the same structure and the same error for all their functions.

This is the exact Error

undefined reference to `Goblin::goblinBattle()'|
undefined reference to `Goblin::goblinBattle()'|
undefined reference to `Goblin::goblinBattle()'|
undefined reference to `Goblin::goblinBattle()'|
undefined reference to `Inventory::inventoryOpen()'|
undefined reference to `Goblin::Goblin()'|
undefined reference to `User::User()'|
undefined reference to `Inventory::Inventory()'|
undefined reference to `Maps::Maps()'|
||=== Build finished: 9 errors, 29 warnings (0 minutes, 0 seconds) ===|


Thanks for reading and helping.
In goblin.cpp, on line 24, you've written:

Goblin::goblinBattle(){

But you've forgotten the function return type, namely void.
I would suspect that a similar problem is causing the undefined reference to Inventory::inventoryOpen() and so on.

Also, what's the point of lines 18 - 21?
Last edited on
In my goblin.h I did make the void goblinBattle(); prototype. When I added the void (void Goblin::goblinBattle()) It came up with the same error. Also i cant add the void to User::User, Maps::Maps, etc. since they are constructors.

Okay.

Right now, I don't see the exact source of your problem. The fact that these are linker errors suggests that you promised you would provide a definition for these functions, but they cannot be found, which can be caused by any one of the following (but not limited to):

1.) You think you've actually added the .cpp file containing the definitions to the project, but you haven't.

2.) The function definition and declaration do not match (misspelling, different parameters / arguments, etc).

I think it would help to clean up your code in order to locate the error, and keep things more maintainable. As of right now, some of your files are including files they don't need to include. For instance, why is goblin.h including itself? Infact, all the include directives from goblin.h should be moved to goblin.cpp - seeing as how they're already there, you can remove lines 4 - 12 of goblin.h.

There needs to be a reason for you to include something - you don't just include every file of your project in every other file of your project - just to "make sure that it works".

I'd also like for you to tell me what lines 18 - 21 of goblin.cpp accomplish. You're creating some different objects, only to use them in the goblinBattle() method, and treating them as "current" objects, which makes no sense. You should probably be passing User, Inventory and Map objects as parameters to the method, or even changing the design overall.
Wow i deleted all the extra #includes and it actually ran! Thanks a lot for the help :D
Topic archived. No new replies allowed.