forward class declaration

Can anybody help me with the following error on build. I thought if you only use a reference to a class type you can place a forward decleration.
player.cpp(111): error C2027: use of undefined type 'Monster'

EDIT: The problem is solved by #including Monster.h in Player.cpp and #including Player.h in Monster.cpp. So do you need to include header files of classes in .cpp files regardless of wether they are passed by reference?

this is Player.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
34
35
36
37
38
//Player.h
#ifndef PLAYER_H
#define PLAYER_H

#include "Weapon.h"
#include <string>

class Monster;

class Player{
public:
	Player();
	bool isDead();
	std::string getName();
	int getArmor();
	void takeDamage(int damage);
	void createClass();
	bool attack(Monster& monster);
	void levelUp();
	void rest();
	void viewStats();
	void victory(int xp);
	void gameover();
	void displayHitPoints();
private:
	std::string mName;
	std::string mClassName;
	int mAccuracy;
	int mHitPoints;
	int mMaxHitPoints;
	int mExpPoints;
	int mNextLevelExp;
	int mLevel;
	int mArmor;
	Weapon mWeapon;
};

#endif 


this is Player.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
//Player.cpp
#include "Player.h"
#include "Random.h"
#include "Weapon.h"
#include <iostream>
using namespace std;

Player::Player(){
	mName = "Default";
	mClassName = "Default";
	mAccuracy = 0;
	mHitPoints = 0;
	mMaxHitPoints = 0;
	mExpPoints = 0;
	mNextLevelExp = 0;
	mLevel = 0;
	mArmor = 0;
	mWeapon.mName = "Default Weapon Name";
	mWeapon.mDamageRange.mHigh = 0;
	mWeapon.mDamageRange.mLow = 0;
}

bool Player::isDead(){
	return mHitPoints <= 0;
}

int Player::getArmor(){
	return mArmor;
}

void Player::takeDamage(int damage){
	mHitPoints -= damage;
}

void Player::createClass(){
	cout << "CHARACTER CLASS GENERATION" << endl;
	cout << "==========================" << endl;

	cout << "Enter your character's name: ";
	getline(cin,mName);

	cout << "Please select a character class number..." << endl;
	cout << "1)Fighter 2)Wizard 3)Cleric 4)Thief: ";
	int characterNum = 1;
	cin  >> characterNum;

	switch(characterNum){
	case 1:
		mClassName = "Fighter";
		mAccuracy = 10;
		mHitPoints = 20;
		mMaxHitPoints = 20;
		mExpPoints = 0;
		mNextLevelExp = 1000;
		mLevel = 1;
		mArmor = 4;
		mWeapon.mName = "Long Sword";
		mWeapon.mDamageRange.mLow = 1;
		mWeapon.mDamageRange.mHigh = 8;
		break;
	case 2:
		mClassName = "Wizard";
		mAccuracy = 5;
		mHitPoints = 10;
		mMaxHitPoints = 10;
		mExpPoints = 0;
		mNextLevelExp = 1000;
		mLevel = 1;
		mArmor = 1;
		mWeapon.mName = "Staff";
		mWeapon.mDamageRange.mLow = 1;
		mWeapon.mDamageRange.mHigh = 4;
		break;
	case 3:
		mClassName = "Cleric";
		mAccuracy = 8;
		mHitPoints = 15;
		mMaxHitPoints = 15;
		mExpPoints = 0;
		mNextLevelExp = 1000;
		mLevel = 1;
		mArmor = 3;
		mWeapon.mName = "Flail";
		mWeapon.mDamageRange.mLow = 1;
		mWeapon.mDamageRange.mHigh = 6;
		break;
	default:
		mClassName = "Thief";
		mAccuracy = 7;
		mHitPoints = 12;
		mMaxHitPoints = 12;
		mExpPoints = 0;
		mNextLevelExp = 1000;
		mLevel = 1;
		mArmor = 2;
		mWeapon.mName = "Short Sword";
		mWeapon.mDamageRange.mLow = 1;
		mWeapon.mDamageRange.mHigh = 6;
		break;
	}
}

bool Player::attack(Monster& monster){
	int selection = 1;
	cout << "1) Attack, 2) Run: ";
	cin  >> selection;
	cout << endl;

	switch(selection){
	case 1:
		cout << "You attack a(n) " << monster.getName() << " with a(n) "
			 << mWeapon.mName << endl;
		if(Random(0,20) < mAccuracy){
			int damage = Random(mWeapon.mDamageRange);
			int totalDamage = damage - monster.getArmor();
			if(totalDamage <= 0){
				cout << "Your attack failed to penetrate " << monster.getName()
					 << "'s armor." << endl;
			}
			else{
				cout << "You attack for " << totalDamage << " damage!" << endl;
				monster.takeDamage(totalDamage);
			}
		}
		else{
			cout << "You miss!" << endl;
		}
		cout << endl;
		break;
	case 2:
		if(Random(1,4) == 1){
			cout << "You run away!" << endl;
			return true;
		}
		else{
			cout << "You could not escape!" << endl;
			break;
		}
	}
	return false;
}

void Player::levelUp(){
	if(mExpPoints >= mNextLevelExp){
		cout << "You gained a level!" << endl;
		mLevel++;
		mNextLevelExp = mLevel * mLevel * 1000;
		mAccuracy += Random(1,3);
		mMaxHitPoints += Random(2,6);
		mArmor += Random(1,2);
		mHitPoints = mMaxHitPoints;
	}
}

void Player::rest(){
	cout << "Resting..." << endl;

	mHitPoints = mMaxHitPoints;
}

void Player::viewStats(){
	cout << "PLAYER STATS" << endl;
	cout << "============" << endl;
	cout << endl;

	cout << "Name				= " << mName << endl;
	cout << "Class				= " << mClassName << endl;
	cout << "Accuracy			= " << mAccuracy << endl;
	cout << "Hitpoints			= " << mHitPoints << endl;
	cout << "Max hitpoints		= " << mMaxHitPoints << endl;
	cout << "Xp					= " << mExpPoints << endl;
	cout << "Xp for next level	= " << mNextLevelExp << endl;
	cout << "Level				= " << mLevel << endl;
	cout << "Armor				= " << mArmor << endl;
	cout << "Weapon name		= " << mWeapon.mName << endl;
	cout << "Weapon damage		= " << mWeapon.mDamageRange.mLow << "-"
		 << mWeapon.mDamageRange.mLow << endl;
	cout << endl;
	cout << "END PLAYER STATS" << endl;
	cout << "================" << endl;
	cout << endl;
}

void Player::victory(int xp){
	cout << "You won the battle!" << endl;
	cout << "You win " << xp << " experience points!" << endl;
	mExpPoints += xp;
}

void Player::gameover(){
	cout << "You died in battle..." << endl << endl;
	cout << "=======================" << endl;
	cout << "GAME OVER!" << endl;
	cout << "=======================" << endl;
	cout << "Press 'q' to quit: " << endl;
	char q = 'q';
	cin  >> q;
	cout << endl;
}

void Player::displayHitPoints(){
	cout << mName << "'s hitpoints = " << mHitPoints << endl;
}


thanks

K
Last edited on
That all looks to be in order but do you ever actually define the class "Monster"?
You can pass a class& without defining it. What you can't do is access its members.
Yes the class Monster is defined in Monster.h.

Summing it up this is how it looked.

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
//Monster.h 
class Player;

class Monster{
public:
     void function(Player& player);
private:
     Player& player;
};

//Player.h 
class Monster;

class Player{
public:
     void function(Monster& monster);
private:
     Monster& monster;
};

//Player.cpp

#include "Player.h"

void function(Monster& monster){}

//Monster.cpp

#include "Monster.h"

void function(Player& player){}


I thought since in the method files the instances of the other classes appear as references only a forward definition is sufficient. I also thought that the forward definition would be taken from including the corresponding header files. But the problem was solved by including the .h files of the used classes explicitly. Not sure if I could explain it well. Any clarification on this matter?

@hamsterman
I understand. I think that was the problem.
Last edited on
None of your other classes headers seem to be including "Monster.h".
They don't need to include Monster.h the problem is solved by including "Monster.h" in the .cpp files only not the other header files. The .h's only need forward declarations and the .cpp's need the actual include file
Last edited on
If you had the "Monster.h" file in the headers you wouldn't need to forward declaration, that's pretty much what I wanted to point out
I also thought that the forward definition would be taken from including the corresponding header files.
It would be nice, but no. In c++ you have to state things explicitly. A & or * work because to pass them program doesn't need any information about the types they point to. Technically all * and &s are the same. Forward declaration is there to tell the compiler that Monster is actually a type and it doesn't need to throw the "undeclared identifier" error.
Thanks hamsterman and computergeek for your help.

Cheers

K
Topic archived. No new replies allowed.