Using a structure in multiple files

Pages: 12
I've just started learning about structures and classes and I don't yet understand how they work...
There are 2 things I want to do

1)
1
2
3
4
5
6
7
8
9
10
struct attributes
{
    //position
    int x, y;
    int new_x, new_y;

    //health
    short HP, MaxHP;

} player, enemy;

Everything with this structure is fine, but what I want to do is something like:

player.HP = 100; player.MaxHP = 100;
(Yes, I want this just for the player and not the enemy)

2) How can I use members of this structure in a different .cpp file like:

cout << "HP: " << player.HP << "/" << player.MaxHP;

I know how to declare other variables in header files, but structures are different...
Last edited on
header file:
1
2
3
4
5
6
7
8
9
10
struct attributes
{
    //position
    int x, y;
    int new_x, new_y;

    //health
    short HP, MaxHP;

};

some other cpp file:
1
2
3
4
//...
attributes player, enemy;
player.HP = 100;//...
//... 

Is this what you wanted?
I really don't think I should define anything in header files, they're for declaring only, right?

Anyway there are a few .cpp files that have #include "common.hpp"

The lines
attributes player, enemy;
player.HP = 100;
player.MaxHP = 100;
in a .cpp file cause the errors:

...\controls.cpp:4:12: error: redefinition of 'attributes player'
In file included from ...\controls.cpp:1:0:
...\common.hpp:19:3: error: 'attributes player' previously declared here
...\controls.cpp:4:20: error: redefinition of 'attributes enemy'
In file included from ...\controls.cpp:1:0:
...\common.hpp:19:11: error: 'attributes enemy' previously declared here
...\controls.cpp:5:1: error: 'player' does not name a type
...\controls.cpp:6:1: error: 'player' does not name a type

controls.cpp contains the code for moving the player and enemies in a char map array
Last edited on
I my code you don't define anything in .h files, you are declarin struct with some fields. And you have to define inline fuctions in headers actually.
Examole of header file which used in several other files and do not causes errors:
http://github.com/TheDarklingWolf/Cataclysm-DDA/blob/master/computer.h
Last edited on
If you look closely at the code Miinipaa posted, you'll see an import difference at line 10.

In your code, by including player and enemy on line 10 you're defining those two variables. You should declare structs in a header, but not define variables based on them in a header. I'm guessing that you didn't remove those variables names from your header, and that is what is causing the errors you posted.
Yes you're right, I'm sorry, I overlooked the fact that you removed the line } player, enemy; from the structure...

I doesn't really work yet though, I gave a poor example in the first post so here's a better one:

common.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef COMMON_HPP_INCLUDED
#define COMMON_HPP_INCLUDED

struct attributes
{
    //position
    int x, y;
    int new_x, new_y;

    //health
    short HP, MaxHP;
};


#endif // COMMON_HPP_INCLUDED 


main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include "common.hpp"

attributes player, enemy;
player.HP = 100;
player.MaxHP = 100;

int main()
{
    std::cout << "HP: " << player.HP << "/" << player.MaxHP << "\n";

return 0;
}


This gives you the errors:

main.cpp:5:1: error: 'player' does not name a type
main.cpp:6:1: error: 'player' does not name a type
Lines 5 and 6 are statements. They should go inside a function.
Do not use global variables without good reason. If you absolutely want to, use constructors:
1
2
3
4
5
6
7
8
struct attrubutes {
//...
    attributes(int x, int y): HP(x), MaxHP(y) {}; //Inline
    attributes(): HP(0), MaxHP(0) {}; // Inline too
};

//...
attributes player(100, 100), enemy;
Or use init function:
1
2
3
4
5
6
7
8
9
10
11
12
13
attributes player, enemy;

//...
void init()
{
     player.HP = 100;
     player.MaxHP = 100;
}

int main()
{
    init()
    //... 
But best solution is to get rid of global variables:
1
2
3
4
5
int main()
{
attributes player, enemy;
player.HP = 100;
//... 
Last edited on
I want to use global variables, because there are actually 2 .cpp files and they both need to access HP and MaxHP.
Maybe I'm doing it wrong and I should make 2 structures - 1 for the player and 1 for enemies,
or 2 structures where 1 stores the positions and 1 stores the health...

... Or maybe I should completely get rid of structures (but... that's where I started...)

Thank you for your detailed answer, though :)
You can pass these structs by reference to the functions that will need them.
I've googled how to do that and I found this: http://www.cplusplus.com/forum/windows/13646/
but I didn't understand much (I'm still a beginner)

So I simply removed HP and MaxHP from the structure and made them as global variables, then declared them as extern in the header file, so they're linked in all files and if the value of HP changes in one, then it will be the same everywhere...

I'm just saying that then I have to have PlayerHP, PlayerMaxHP, EnemyHP and EnemyMaxHP... There's no problem, but I thought I should use structures...
Last edited on
Try something like this maybe:

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
// a.cpp
#include "a.h"
void AttributeTest(attributes& a) {
// '&' there stands for 'Pass by Reference'
}

// a.h
#include "Attributes.h"
void AttributeTest(attributes& a);
// '&' there stands for 'Pass by Reference'

// b.cpp
#include "b.h"
void attriButeTest(attributes a) {
// Without '&': Pass by Value. The variable is copied, and you will not modify
// it, except inside this function.
// E.G.: a.HP = 4;
// Outside this function, a will not change, they are two different vars.
}

// b.h
#include "Attributes.h"
void attriButeTest(attributes a);
// Without '&': Pass by Value. The variable is copied, and you will not modify
// it, except inside this function.

// Attributes.h
#ifndef ATTRIBUTES_H_VIDMINAS
// unique name, you can do it for all .h files
#define ATTRIBUTES_H_VIDMINAS
struct attributes {
    
};
#endif

// main.cpp
#include "Attributes.h"
#include "a.h"
#include "b.h"

int main()
{
    attributes attr;
    AttributeTest(attr); // Pass by ref, can be edited
    attriButeTest(attr); // Copies attr, will never be edited
    return 0;
}
Last edited on
Thank you so much guys for your time, I'm sorry I still don't understand - maybe I'm just too confused. I'm sorry.
I'll take a different approach to this, I'll just paste most of the code so you can tell me how to change it, ok?

This is maps.cpp
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
#include "common.hpp"

char (* Map)[40][40];

char map1 [40][40] =
{"##################",
 "#      #         #",
 "#      #         !",
 "#  #   #     #####",
 "#  #   #     #   #",
 "#@ #   #         #",
 "####   #         #",
 "#      #######   #",
 "#                #",
 "##################"};

char map2[40][40] =
{"##################",
 "@  #          +  !",
 "#  #        ######",
 "#  #       #######",
 "#  #      ########",
 "#**#     #########",
 "#  #    ##########",
 "#  #   ###########",
 "#     ############",
 "##################"};

char map3[40][40] =
{"#####################################",
 "#                                   #",
 "#                                   #",
 "#                                   #",
 "#     S                             #",
 "#                                   #",
 "#                                   #",
 "#                                   #",
 "######                     S        #",
 "#                                   #",
 "#    #                              #",
 "#    #                              #",
 " @   #                              #",
 "#    #                              #",
 "#####################################"};

void play()
{
    ClearScreen();
    cout << "--------TUTORIAL 1";
    cout << "\n\n\tWelcome to CliX :)";
    cout << "\n\tYou should use this room to practice moving around.";
    cout << "\n\tOnce you're confident with the controls head for the exit (!)";
    cout << "\n\tBye for now!";
    cin.get();

while (running and stage == 1)
{
    Map = &map1;

    ClearScreen();
    for (int i = 0; i < 10; i++)
    {
	cout << (*Map)[i] << "\n";
    }
    cout << "HP: " << HP << "/" << MaxHP;
    controls();
}

    ClearScreen();
    cout << "--------TUTORIAL 2";
    cout << "\n\n\tBeware of the traps '*' and collect potions '+' to heal up";
    cin.get();

while (running and stage == 2)
{
    Map = &map2;

    ClearScreen();
    for (int i = 0; i < 10; i++)
    {
	cout << (*Map)[i] << "\n";
    }
    cout << "HP: " << HP << "/" << MaxHP;
    controls();
}

    ClearScreen();
    cout << "--------TUTORIAL 3";
    cout << "\n\n\tLook out for snakes (S), they could be dangerous!";
    cin.get();

while (running and stage == 3)
{
    Map = &map3;

    ClearScreen();
    for (int i = 0; i < 15; i++)
    {
	cout << (*Map)[i] << "\n";
    }
    cout << "\t\tHP: " << HP << "/" << MaxHP;
    controls();
}

}


This is controls.cpp:
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
#include "common.hpp"
#include <ctime>

short gamespeed = 120;
short stage = 1;
short random = 0;

struct attributes
{
    //position
    int x, y;
    int new_x, new_y;
}player, enemy;

short HP = 100;
short MaxHP = 100;

void controls()
{
    for (player.y = 0; player.y < 40; player.y++)
    {
    for (player.x = 0; player.x < 40; player.x++)
    {
        switch ((*Map)[player.y][player.x])
        {
            case '#': //Uses ASCII characters instead of '#' for (*Map) borders
            if (stage == 1 or stage == 2)
            { (*Map)[player.y][player.x] = 178; break; }

            if (stage == 3)
            { (*Map)[player.y][player.x] = 225; break; }


            case '@':
            player.new_x = player.x; player.new_y = player.y;

            if (GetAsyncKeyState(VK_UP) != 0)    {player.new_y -= 1;}
            if (GetAsyncKeyState(VK_DOWN) != 0)  {player.new_y += 1;}
            if (GetAsyncKeyState(VK_LEFT) != 0)  {player.new_x -= 1;}
            if (GetAsyncKeyState(VK_RIGHT) != 0) {player.new_x += 1;}

                switch ((*Map)[player.new_y][player.new_x])
                {
                    case ' ': //Moves the player
                    (*Map)[player.y][player.x] = ' ';
                    player.x = player.new_x; player.y = player.new_y;
                    (*Map)[player.new_y][player.new_x] = '@';
                    break;

                    case '*': //Trap - takes away 10 health and moves the player to it's location
                    if ( HP > 10 ) { HP -= 10; }
                    //else (HP <= 10) //game over
                    (*Map)[player.y][player.x] = ' ';
                    player.x = player.new_x; player.y = player.new_y;
                    (*Map)[player.new_y][player.new_x] = '@';
                    break;

                    case '+': //Potion - same as trap but adds 20 health instead
                    if ( HP <= MaxHP -20) {HP += 20;}
                    else if ( HP >= MaxHP -20) {HP = MaxHP;}
                    (*Map)[player.y][player.x] = ' ';
                    player.x = player.new_x; player.y = player.new_y;
                    (*Map)[player.new_y][player.new_x] = '@';
                    break;

                    case '!': //Exit - moves the player to the next (*Map)
                    stage += 1; break;
                }
            break;
        }
    }
    }

    for (enemy.y = 0; enemy.y < 40; enemy.y++)
    {
    for (enemy.x = 0; enemy.x < 40; enemy.x++)
    {
        switch ((*Map)[enemy.y][enemy.x])
        {
            case 'S':
            enemy.new_x = enemy.x; enemy.new_y = enemy.y;

            random = rand() % 4 + 1;
            if (random == 1) {enemy.new_y -= 1;}
            if (random == 2) {enemy.new_y += 1;}
            if (random == 3) {enemy.new_x -= 1;}
            if (random == 4) {enemy.new_x += 1;}

            switch((*Map)[enemy.new_y][enemy.new_x])
            {
                case ' ':
                (*Map)[enemy.y][enemy.x] = ' ';
                enemy.x = enemy.new_x; enemy.y = enemy.new_y;
                (*Map)[enemy.new_y][enemy.new_x] = 'S';
                break;

                default:
                random = 0;
                break;
            }
            break;
        }
    }
    }
Sleep(gamespeed); //Pauses slightly to reduce flicker
}


And this is common.hpp:
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
#pragma once
#ifndef COMMON_HPP_INCLUDED
#define COMMON_HPP_INCLUDED

#include <iostream>
#include <windows.h>

using std::cout; using std::cin;

// Functions and variables from "other.cpp"
extern void ClearScreen();
extern CHAR getkey (VOID);

// Functions and variables from "controls.cpp"
extern short random, stage, gamespeed;
extern short HP, MaxHP;
extern void controls();

// Functions and variables from "main.cpp"
extern bool running;
extern char menu;

extern void instructions();

// Functions and variables from "maps.cpp"
extern char (* Map)[40][40];
extern char map1[40][40];
extern char map2[40][40];
extern char map3[40][40];

extern void play();

#endif // COMMON_HPP_INCLUDED 


There is more code, but it is irrelevant so I won't post it (whoa, almost exceeded the length limit here)...

The batle system isn't quite ready yet, so there is no need for enemyHP and enemyMaxHP, but I will get there eventually which is why I want a fully functional structure.

By the way the current code works as HP and MaxHP are simply variables of type short and everything is fine with the positioning variables, because they're only used in controls.cpp
Last edited on
I have reviewed the source code of many different simple console games and I decided I should create different classes for the player and all kinds of enemies as they will provide me with all the functionality I need.

All in all, I don't need such a structure at all, so for now - problem solved :)
You still risk to find yourself with this question again sooner or later.

Because a class IS a structure, in C++.
Yep, you're right :D
Nobody was helping me out when I wrote my code, so I decided I'd reactivate this topic later, when I had more info...

Now if anybody can tell me how to use the structure in the code I wrote above, please do, it will be useful later.

Also as you see I only have one header file, common.hpp, please tell me if I should make a corresponding header file for each .cpp file (now I don't really see the point, because there isn't much stuff to add to common.hpp)
Last edited on
Well, as long as your 'attributes' does not have any functions:

1
2
3
4
5
6
7
8
9
10
// Attributes.hpp
#pragma once
struct attributes {
    unsigned int HP;
    unsigned int MaxHP;
    unsigned int PosX;
    unsigned int PosY;
    unsigned int DirectionX;
    unsigned int DirectionY;
};


1
2
3
4
5
6
// Globals.cpp
#include "Globals.hpp"
#include <vector>

attributes Player;
std::vector<attributes> Enemies;


1
2
3
4
5
6
7
// Globals.hpp
#pragma once
#include "Attributes.hpp"
#include <vector>

extern attributes Player;
extern std::vector<attributes> Enemies;


At this point, whenever you need to access Player and the array of enemies 'Enemies', you just need to remember to include Globals.hpp

Globals.hpp will then include Attributes.hpp

The 'extern' variables do not define the variables themself, they just declare them.

They will be defined in Globals.cpp

If this is not enough, explicitly say in which part you are stuck, it's kinda hard and I feel I'm repeating myself.
Last edited on
No thanks, I get it now, you're kind of going too easy on me when explaining what extern is. I'm just a self taught programmer so I may know some things that are more complicated, and I may lack some essential things.

If I stumble upon any more problems I'll ask again.

And thank you very much :)
Well, 'extern' is the declaration of a variable.
It does not define it, anyways.

It's like, for functions:

1
2
int TestFunction(); // <- Equivalent of a 'extern' variable
int TestFunction(){}; // <- Equivalent of a common variable 
Last edited on
Yeah, lol you're absolutely right! I have no idea why I declared every single function as extern in the header :)
Pages: 12