Constructor

I am starting a project that will be my first using inheritance, and I am currently on the base class called creature. Here, I need to have a default constructor that will initialize an object to "human" with 10 point of strength, and 10 hit points. For the values of ten, they are being initialized directly inside the constructor, but for an object being a default value of "human" I am calling a member function and I think the problem lies in this connection somewhere but I'm not sure what it is. I am getting an error that says:

Creature.h(15): error C3646: 'getSpecies': unknown override specifier

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
 namespace cs_creature
{
	class Creature
	{
	private:
		int type;               // 0 Human, 1 Cyberdemon, 2 Balrog, 3 elf
		int strength;           // how much damage this Creature inflicts
		int hitpoints;          // how much damage this Creature can sustain
		string getSpecies(int type) const;    // returns the type of the species

	public:
		Creature();             // initialize to Human, 10 strength, 10 hitpoints
		Creature();
		int getDamage() const;         // returns the amount of damage this Creature
									 // inflicts in one round of combat

			// also include appropriate accessors and mutators    
	};
}




Creature::Creature()
	{ 
		int human = 0;
		getSpecies(human);

		strength = 10;
		hitpoints = 10;
	}




string Creature::getSpecies(int type)const
	{
		switch (type) {
		case 0: return "Human";
		case 1: return "Cyberdemon";
		case 2: return "Balrog";
		case 3: return "Elf";
		}
		return "unknown";
	}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Creature
{
private:
  // C++11 default member initializers
  int type {0}; // this could be an enumeration type
  int strength {10};
  int hitpoints {10};
  // string getSpecies(int type) const;
public:
  Creature() = default;
  Creature( int t, int s, int h );
  int getDamage() const;
};

// initializer list syntax
Creature::Creature( int t, int s, int h )
  : type{t}, strength{s}, hitpoints{h}
{
}


Your getSpecies makes no sense. Only Creatures can call it. It does not tell the type of this creature. When you use it, you discard the return value.
The getSpecies function is given by the instructor and there will be creatures calling it. I am in the beginning stage and just trying to figure out how objects are to get initialized to the default value of "human." So, my thought was to call the getSpecies but it sounds that that is incorrect and only objects can call it.

I don't think I am allowed to initialize type {0} inside the class; would that make the getSpecies function so it couldn't be called with other values? I'm sorry, I haven't studied enumerated types yet so this part I am not familiar with.

What do you think about adding a new string data member that will allow me to assign the string literal of "Human" inside the constructor?

Actually, I tried running this and I get the same error. I need to get a better understanding of what is going on.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

private:
		int type;               // 0 Human, 1 Cyberdemon, 2 Balrog, 3 elf
		int strength;           // how much damage this Creature inflicts
		int hitpoints;          // how much damage this Creature can sustain
		string getSpecies(int type) const;    // returns the type of the species
		string creature;

}




Creature::Creature()
	{ 
		strength = 10;
		hitpoints = 10;
		
		creature = "Human";
	}
The error has probably to do with the namespace cs_creature. You need to encompass the implemented functions as well (line 24 onwards).

For getSpecies(...): Why do you pass type? There is alread a member variable type. This way it is rather confusing what getSpecies(...) actually is supposed to do.
I don't think I am allowed to initialize type {0} inside the class

Why not? That is valid modern C++. If you are learning C++, then you should learn modern C++ (although there is job market for legacy code maintainers too).

I presume the goal is:
1
2
3
4
int main() {
  Creature jack;
  // Assert: jack.type==0, jack.strength==10, jack.hitpoints==10
}

That has nothing to do with the getSpecies. The getSpecies does take a parameter that has name 'type', but that is not the member 'type' of every Creature. Same name re-used in different context.

A problem with that function is that we cannot:
cout << jack.getSpecies();
We cannot get the string representation of the type of an existing Creature object. We have to:
cout << jack.getSpecies( 42 );
In other words, we would have to get the type of jack and then call the function with the type as argument (except that it is a private member).

What the function does is to convert a numeric value into text. A mapping. A lookup.
It could be a standalone function:
1
2
3
4
5
string getSpecies(int type);

int main() {
  cout << getSpecies( 42 );
}

It could be a static member:
1
2
3
4
5
6
7
8
class Creature {
public:
  static string getSpecies(int type);
};

int main() {
  cout << Creature::getSpecies( 42 ); // We don't need any creatures in order to test whether 0 is "Human"
}


Having both 'type' and 'creature' member variables is redundant, i.e. waste of memory, since we can always call getSpecies to convert type to text.


Finally:
1
2
3
4
Creature::Creature()
{ 
	strength = 10; // this is assignment, not initialization
}


1
2
3
4
5
Creature::Creature()
 : strength{10} // this is initialization
{
 // nothing to do here 
}
I appreciate your guys feedback. I like being exposed to the "modern" style, but since my instructor is using this style I feel that I should go with that. Hopefully the classes will transition to a modern style.

For the initialization, if the strength = 10 was assigned at the same time it was declared then that would be initialization correct? I was assuming that initialization was just the first time a variable takes on a value. I thought it could be declared in one spot and initialized in another spot, and sounds like your saying that would be assignment.

Moving along with my project, I think I may not have been asking the correct questions to begin with. Turns out that the instructions want the variable type to be eliminated though the implementation of inheritance. In addition to the getSpecies function there is also a getDamage function that uses this variable. I'll post the code.

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
int Creature::getDamage() const {
    int damage;
    
    // All Creatures inflict damage which is a random number up to their strength
    damage = (rand() % strength) + 1;
    cout << getSpecies() << " attacks for " << damage << " points!" << endl;
    
    // Demons can inflict damage of 50 with a 25% chance
    if (type == 2 || type == 1){
        if (rand() % 4 == 0) {
            damage = damage + 50;
            cout << "Demonic attack inflicts 50 additional damage points!" << endl;
        }
    }
    
    // Elves inflict double magical damage with a 50% chance
    if (type == 3) {
        if ((rand() % 2) == 0) {
            cout << "Magical attack inflicts " << damage << " additional damage points!" << endl;
            damage *= 2;
        }
    }
    
    // Balrogs are so fast they get to attack twice
    if (type == 2) {
        int damage2 = (rand() % strength) + 1;
        cout << "Balrog speed attack inflicts " << damage2 << " additional damage points!" << endl;
        damage += damage2;
    }
    
    return damage;
}
One problem with this implementation is that it is unwieldy to add new Creatures. Rewrite the class to use inheritance, which will eliminate the need for the variable "type". The Creature class should be the base class. The classes Demon, Elf, and Human should be derived from Creature. The classes Cyberdemon and Balrog should be derived from Demon. You will need to rewrite the getSpecies() and getDamage() functions so they are appropriate for each class.


I understand that I need to make both .cpp and .h files for each of the creatures, but I don't understand how data is supposed to be communicated by eliminating the variable type.
About "modern":
Creature::Creature()
: type(0), strength(10) // class member initializer list
{
}

That (class member initializer list syntax) is not "modern". It is as old as C++ Standard.

The brace initializer syntax did appear in C++11.


There is difference between initialization and assignment. You can (have to) initialize a const, but you cannot assign to it.
1
2
const int x = 7; // ok
x = 42; // error: cannot modify a constant object 


1
2
3
4
5
6
7
8
class MyInt {
  const int x;
  MyInt()
  : x(7) // ok
  {
    x = 42; // error
  }
};



Without if (type == ... ) implies inheritance and virtual functions. All these Creatures can say "hello" in their own way without member variable "type":
1
2
3
4
5
6
7
8
9
10
11
struct Creature {
  virtual string hello() { return "Unknown"; }
};

struct Human : public Creature {
  string hello() { return "Human"; }
};

struct Daemon : public Creature {
  string hello() { return "Daemon"; }
};
Thank you! I appreciate the insight.
Topic archived. No new replies allowed.