Virtual problems

I'm having trouble with my virtual function, but I'm doing the same thing as my professor did in our video lecture. I get these errors:

error C2352: 'Character::printStats' : illegal call of non-static member function

see declaration of 'Character::printStats'

error C2664: 'doTest' : cannot convert parameter 1 from 'Monster' to 'Character &'

Can anyone guide me through my errors?

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
#include <iostream>
#include <string>

using namespace std;

/***********************************
*         Character Class          *
***********************************/

class Character
{
public:
	Character();
	~Character();
	Character(int, int, int, int, int, int);
	void setStats(int, int, int, int, int, int);
	int getStats(int &, int &, int &, int &, int &, int &);
	virtual void printStats();  // virtual function

private:
	int str, dex, con, inte, wis, cha;
};


/***********************************
*    Character Class Functions     *
***********************************/


Character::Character()
{
	str = 8; dex = 8; con = 0; inte = 8; wis = 8; cha = 8;
}

Character::~Character()
{}

Character::Character(int Str, int Dex, int Con, int Inte, int Wis, int Cha)
{
	str = Str; dex = Dex; con = Con; inte = Inte; wis = Wis; cha = Cha;
}

void Character::setStats(int Str, int Dex, int Con, int Inte, int Wis, int Cha)
{
	str = Str; dex = Dex; con = Con; inte = Inte; wis = Wis; cha = Cha;
}

int Character::getStats(int &, int &, int &, int &, int &, int &)
{
	return str, dex, con, inte, wis, cha;
}

void Character::printStats()
{
	getStats(str, dex, con, inte, wis, cha);
	if(con != 0)
		cout << "\nA basic DnD character for creation has " << str << " strength, " << 
		dex << " dexterity, " << con << " constitution, " << inte << " intelligence, " 
		<< wis << " wisdom and " << cha << " charisma." << endl << endl;
	
	else if(cha == 6)
	cout << str << " strength, " << dex << " dexterity, " << con << " constitution, " 
	<< inte << " intelligence, " << wis << " wisdom and " << cha << " charisma." << endl << endl;

	else
		cout << "\nA dead basic DND character has " << str << " strength, " << 
		dex << " dexterity, " << con << " constitution, " << inte << " intelligence, " 
		<< wis << " wisdom and " << cha << " charisma." << endl << endl;

}


/***********************************
*          Monster Class           *
***********************************/


class Monster
{
public:
	Monster(string enemy = "", int lvl = 0, int str = 0, int dex = 0, int con = 0, int inte = 0, int wis = 0, int cha = 0); // constructor 
	void setMonster(string enemy, int lvl, int str, int dex, int con, int inte, int wis, int cha);
	void printStats();

private:
	Character monChar; // composite object
	int lvl;
	string enemy;
};


/***********************************
*    Monster Class Functions       *
***********************************/

Monster::Monster(string Enemy, int Lvl, int str, int dex, int con, int inte, int wis, int cha)
:monChar(str, dex, con, inte, wis, cha)
{
	enemy = Enemy;
	lvl = Lvl;
}

void Monster::setMonster(string Enemy, int Lvl, int Str, int Dex, int Con, int Inte, int Wis, int Cha)
{
	enemy = Enemy;
	lvl = Lvl;
	monChar.setStats(Str, Dex, Con, Inte, Wis, Cha);
}

void Monster::printStats()
{
	cout << "A " << enemy << " of level " << lvl << " may have stats of "; 
	Character::printStats();
	cout << endl;
}


/***********************************
*      Stand Alone Function        *
***********************************/

void doTest(Character &input)
{
	input.printStats();
}


/***********************************
*           Main                   *
***********************************/


int main()
{
	Character guy; // dead character stats for 0 lv.
	guy.setStats(8, 8, 8, 8, 8, 8); // basic character stats for 0 lv.
	doTest(guy);
	
	Monster thing;
	thing.setMonster("half-orc", 3, 10, 8, 8, 6, 8, 6);
	doTest(thing);

}




In total I have to have an overloaded function, polymorphism and a composite object. I can get past one of the errors if I use monChar.printStats();
I still get the - cannot convert parameter 1 from 'Monster' to 'Character &' - though. I have to add another class to the whole program to meet the professor's requirements, but I'll work on that after I get through this.

1. Create a new project that consists of at least two classes: a base class and a derived class. It should also contain at least one more class that will be used to instantiate the composite member of either the base or the derived class.

2. The base class and derived classes should have at least one data member and two functions each in addition to the constructor. The derived class should have at least one overloaded function and a data member which is a member of another class (composition).
Last edited on
Which lines are the errors on?
Well, Monster isn't derived from Character, it has a Character member. It can't be used as a Character object, which is what doTest() is expecting.

If you intend Monster to be a Character, you need to change it to class Monster : public Character. As it is, Monster has a Character, which I'm not sure is what you want.

If you wanted to add functionality to the Character class (have it be more like a playable-character) you could create a new class like so: class PlayableCharacter : public Character. This would let you have both Monsters and PlayableCharacters have things like stats in common.

The non-static member function error comes from the fact that using :: to call the function is used for static functions, since they're non-specific to particular objects (meaning you don't use the dot operator, like myObject.someFunc();).

Your Monster::printStats() should instead do monChar.printStats().
I can't believe I forgot to put my inheritance back in. I was making changes during creation of the second class and missed it all together. I was going to make it a Jobs class for Warrior, Mage, etc. Thank you.
But now there is a print problem. I wanted it to print
"A half-orc of level 3 may have stats of str 10, dex 8, con 8, inte 6, wis 8, cha 6."

But instead it prints out:

"A half-orc of level 3 may have stats of A basic DND character for creation has strength 10, dexterity 8, constitution 8, intelligence 6, wisdom 8 and charisma 6."

I thought the virtual function was to change what is chosen for output when specified.
Well, check your Monster::printStats() function. It prints the name and level, then makes a call to monChar.printStats(), right? You'd have to add to Monster::printStats() so that it can print everything you want without needing to call Character::printStats().
Oh, ok. I need to use a little from both, so I'll just edit what is printed for the monster stats print out. Thank you for helping me understand this better. Now I'm off to make the third class.
Here's my code. I have to add some comments to different areas and section this into headers and .cpp files. It looks a little sloppy... I changed the job idea to hit points. Thanks again for the help.

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
#include <iostream>
#include <string>

using namespace std;

/***********************************
*            Hp Class             *
***********************************/

class Hp
{
public:
	Hp();
	Hp(int);
	void setHp(int);
	int getHp(int &);
	void printHp();

private:
	int life;	
};

/***********************************
*  Hp Class Function Definitions   *
***********************************/

Hp::Hp()
{
	life = 0;
}

Hp::Hp(int Life)
{
	life = Life;
}

void Hp::setHp(int Life)
{
	life = Life;
}

int Hp::getHp(int &)
{
	return life;
}

void Hp::printHp()
{
	cout << life;
}

/***********************************
*         Character Class          *
***********************************/

class Character
{
public:
	Character();
	~Character();
	Character(int, int, int, int, int, int);
	void setStats(int, int, int, int, int, int);
	int getStats(int &, int &, int &, int &, int &, int &);
	virtual void printStats();  // virtual function

private:
	int str, dex, con, inte, wis, cha;
};

/***************************************
* Character Class Function Definitions *
***************************************/


Character::Character()
{
	str = 9; dex = 8; con = 7; inte = 9; wis = 7; cha = 8;
}

Character::~Character()
{}

Character::Character(int Str, int Dex, int Con, int Inte, int Wis, int Cha)
{
	str = Str; dex = Dex; con = Con; inte = Inte; wis = Wis; cha = Cha;
}

void Character::setStats(int Str, int Dex, int Con, int Inte, int Wis, int Cha)
{
	str = Str; dex = Dex; con = Con; inte = Inte; wis = Wis; cha = Cha;
}

int Character::getStats(int &, int &, int &, int &, int &, int &)
{
	return str, dex, con, inte, wis, cha;
}

void Character::printStats()
{
	getStats(str, dex, con, inte, wis, cha);
	cout << str << " strength, " << dex << " dexterity, " << con << " constitution, " 
		<< inte << " intelligence, " << wis << " wisdom and " << cha << " charisma";
}

/***********************************
*          Monster Class           *
***********************************/


class Monster: public Character
{
public:
	Monster(string enemy = "", int lvl = 0, int str = 0, int dex = 0, int con = 0, int inte = 0, int wis = 0, int cha = 0, int life = 0); // constructor 
	void setMonster(string enemy, int lvl, int str, int dex, int con, int inte, int wis, int cha, int life);
	void printStats();

private:
	Character monChar; // composite object
	Hp blood;
	int lvl;
	string enemy;
};

/*************************************
* Monster Class Function Definitions *
*************************************/

Monster::Monster(string Enemy, int Lvl, int str, int dex, int con, int inte, int wis, int cha, int life)
:monChar(str, dex, con, inte, wis, cha), blood(life)
{
	enemy = Enemy;
	lvl = Lvl;
}

void Monster::setMonster(string Enemy, int Lvl, int Str, int Dex, int Con, int Inte, int Wis, int Cha, int Life)
{
	enemy = Enemy;
	lvl = Lvl;
	monChar.setStats(Str, Dex, Con, Inte, Wis, Cha);
	blood.setHp(Life);
}

void Monster::printStats()
{
	cout << "A " << enemy << " of level " << lvl << " may have stats of: "; 
	monChar.printStats();
	cout << ", along with a possible ";
	blood.printHp();
	cout << " hit points of life.";
	cout << endl;
}

/***********************************
*      Stand Alone Function        *
***********************************/

void doTest(Character &input)
{
		input.printStats();
}

/***********************************
*           Main                   *
***********************************/


int main()
{
	Character guy; // dead character stats for 0 lv.
	guy.setStats(8, 8, 8, 8, 8, 8); // basic character stats for 0 lv.
	cout << "A basic character may have little life, ";
	doTest(guy);
	cout << "." << endl << endl;
	
	Monster thing;
	thing.setMonster("half-orc", 3, 10, 8, 8, 6, 8, 6, 32);
	doTest(thing);

}

Last edited on
Nice job! There's a couple things that are a little strange about your code, even though it works:

Having an HP class specific to monsters is a little awkward to me; it seems to me that health would be something all characters should have. (I noticed from your second requirement that you needed to design it like this, but maybe you should have something more Monster-specific? Just a thought.)

Also, since you indicated in your comments the basic stats for a lv 0 character are all 8, why not have that be the default in the constructor? Or have all the stats begin at 0 in the constructor? The numbers you use right now are a little weird, to me.

Finally, you shouldn't have Monster own a Character (monChar) if it IS a character. Although there may be cases where you want that kind of behavior, this isn't one. Since it has a character, it has two sets of stats - one set from its parent class, and another from its member monChar. Get rid of monChar, and just call Character::printStats() normally from within Monster::printStats(). Using :: will work now since Monster inherits from Character.
I did change the 8s to something else, more for a different output than anything. I had to show that each function worked and I didn't want a character with 0 for everything.

1
2
3
4
5
Character::Character()
{
	str = 9; dex = 8; con = 7; inte = 9; wis = 7; cha = 8;
}


I didn't want the monster class for something playable, just that it had stats. I see what you mean now about the double stats, because I tried a print out and I got double of what I was trying for. I just fixed the code, and you're right- Character should have HP, and I just didn't link it. Thanks!
Topic archived. No new replies allowed.