-1

I'm trying to learn C++ and currently I'm trying to know how to implement an object composition in this language.

I have a Character class which is inherited by a Hero and a Monster class.

A Character has a NormalAbility and a SpecialAbility.

I've made the NormalAbility and SpecialAbility classes and both are inheriting an Ability superclass.

My problem is that when I put the #include "Character.h" in Ability.h the normalAbility and specialAbility variables in Character.h don't get recognized as their respected classes. Errors such as "syntax error : identifier string" shows in the headers of both Ability inherited classes

Here's my code:

Character.h

#pragma once
#include <string>
#include "NormalAbility.h"
#include "SpecialAbility.h"

using namespace std;

class Character
{
public:
   Character(string name, string type, int hp, NormalAbility na, 
             SpecialAbility sa);
   bool isDead();
   void damage(int amt);
   void heal(int amt);
   void attack(Character* c, int amt);

private:
   string name;
   string type;
   int hp;
   int maxHp;
   NormalAbility* normalAblity;
   SpecialAbility* specialAbility;
}

Character.cpp

#include "Character.h"
#include <iostream>

Character::Character(string name, string type, int hp, NormalAbility* na, 
             SpecialAbility* sa)
{
   this->name = name;
   this->type = type;
   this->maxHp = hp;
   this->hp = hp;
   normalAbility = na;
   specialAbility = sa;
}

bool Character::isDead(){
   return hp <= 0;
}

void Character::damage(int amt){
   if (hp > 0){
      hp -= amt;
   }
   else{
      hp = 0;
   }
}

void Character::heal(int amt){
   if (hp + amt > maxHp){
      hp = maxHp;
   }
   else{
      hp += amt;
   }
}

void Character::attack(Character* c, int amt){
   c->damage(amt);
}

Hero.h

#pragma once
#include "Character.h"
#include <string>

using namespace std;

class Hero :
   public Character
{
public:
   Hero(string name, int hp);
}

Hero.cpp

#include "Hero.h"
#include <iostream>

Hero::Hero(string name, int hp) 
     : Character(name, "Hero", hp)
{
}

Ability.h

#pragma once
#include <string>
#include "Character.h"

using namespace std;

class Ability
{
public:
   Ability(string name, string type, Character* owner);
   void levelUp();
private:
   string name;
   string type;
   int level;
   Character* owner;
}

Ability.cpp

#include "Ability.h"

Ability::Ability(string name, string type, Character* owner)
{
   this->name = name;
   this->type = type;
   this->owner = owner;
   level = 1;
}

void Ability::levelUp(){
   level++;
}

NormalAbility.h

#pragma once
#include "Ability.h"
#include <string>

using namespace std;

class NormalAbility :
   public Ability
{
public:
   NormalAbility(string name);
}

NormalAbility.cpp

#pragma once
#include "NormalAbility.h"
#include <string>

using namespace std;

NormalAbility::NormalAbility(string name) : Ability(name, "Normal")
{
  //some codes
}
noxfur
  • 331
  • 1
  • 5
  • 15
  • What is the specific symptom? – Oliver Charlesworth Jun 26 '15 at 15:50
  • 2
    "Doesn't seem to get recognized..." meaning? You can't call the data...can't fill the data...more specific please. – Adam Jun 26 '15 at 15:51
  • When I put the `#include "Character.h"` in the `Ability.h` the normalAbility and specialAbility variables don't get recognized as their respected classes. Errors such as "syntax error : identifier string" shows in the headers of both `Ability` inherited classes – noxfur Jun 26 '15 at 15:55
  • Can you share the whole error? – DGomez Jun 26 '15 at 15:59
  • 1
    If you put `#include "Character.h"` in `Ability.h` you will have a circular dependency. You'd need to forward-declare somewhere. Your `Character`'s declaration also does not match its definition, as DGomez mentioned. – RJFalconer Jun 26 '15 at 15:59
  • 1
    Yeah, if that is the case you can use a Forward Declaration of Character in the header of Ability and include the "Character.h" in the Ability.cpp, that should fix the dependency problem – DGomez Jun 26 '15 at 16:02
  • I see... can you please give a suggestion on how I would fix this? I was planning to make it bidirectional. – noxfur Jun 26 '15 at 16:04
  • Thanks! Finally fixed it. I'm not really familiar with Forward Declaration. Looked it up and finally fixed my problem. – noxfur Jun 26 '15 at 16:20

1 Answers1

2

This way you avoid the circular include of the .h files, because you're including it in the .cpp, and in the .h you're saying that, "Character exists but don't care about his definition right now"

Ability.h

#pragma once
#include <string>


class Character;

using namespace std;

class Ability
{
public:
   Ability(string name, string type, Character* owner);
   void levelUp();
private:
   string name;
   string type;
   int level;
   Character* owner;
}

Ability.cpp

#include "Ability.h"
#include "Character.h"

Ability::Ability(string name, string type, Character* owner)
{
   this->name = name;
   this->type = type;
   this->owner = owner;
   level = 1;
}

void Ability::levelUp(){
   level++;
}
DGomez
  • 1,450
  • 9
  • 25
  • Please, note that "#pragma once" is not required, and should not be used since it is compiler dependant. Instead, replace it with #ifndef __ABILITY_H__ and #define __ABILITY_H__ includes barriers to avoid including more than once. Then your answer would be perfect. – LoPiTaL Jun 26 '15 at 16:11
  • Thanks for the tip. I'm studying C++ for UE4. My teacher mentioned that using `#pragma once` isn't the conventional way but it's fine since UE4 uses it. – noxfur Jun 26 '15 at 16:29
  • 1
    @LoPiTaL `#pragma once` being compiler dependent doesn't mean it shouldn't be used. It might not be standard, but it's a lot more elegant than traditional include guards and is widely supported. More info (including some good reasons not to use it) here: http://stackoverflow.com/questions/23696115/is-pragma-once-part-of-the-c11-standard – Etienne Maheu Jun 26 '15 at 16:36