Доступ к аргументам подкласса - PullRequest
0 голосов
/ 22 апреля 2020

Недавно я добавил подкласса Enemy в свой класс Character, который получает еще два параметра в своем конструкторе.

Enemy::Enemy(const string &name, int health, int stamina, bool _isEnemy, bool _roaming) : Character(name, health, stamina), isEnemy(_isEnemy), roaming(_roaming){
    this->name = name;
    this->stamina = stamina;
    this->isEnemy = _isEnemy;
    this->roaming = _roaming;

Мой класс символов также имеет геттеры и сеттеры для выносливости здоровья и текущей комнаты. Тогда в моем главном есть вектор указателей типа Enemy, и я просто использую простое для l oop, чтобы выбрать и противника, и вызвать специфическую c функцию, такую ​​как getCurrentRoom ()

for(int i = 0; i < enemies.size(); i++) {
            if(currentRoom == enemies[i]->getCurrentRoom()) {
                cout << enemies[i]->getName() << " HP: " << enemies[i]->getHealth() << " " << enemies[i]->getName()
                     << " ST: " << enemies[i]->getStamina() << endl;
            }

This просто показывает врагов HP и ST, если они находятся в одной комнате с игроком. Но при отладке, чтобы увидеть значения врага, например, он имеет Объект персонажа, который, как я предполагаю, существует, потому что он является базовым классом, но также имеет значения из своего собственного класса Enemy с неправильным здоровьем, и он не может чтобы получить доступ к своей текущей комнате

getCurrentRoom () просто возвращает указатель типа комнаты. Может быть, причина, по которой у подкласса нет доступа, заключается в том, что возвращаемый указатель находится в частном порядке в Character.h?

1 Ответ

0 голосов
/ 22 апреля 2020

Если getters и setters, объявленные в классе Character, являются publi c, а не чисто виртуальными, и класс Enemy публично наследуется от Character, например:

class Enemy : public Character

класс Enemy не нуждается (и не должен иметь) getters и setters для переменных имени, здоровья и выносливости. Проверьте, выполняются ли эти условия.

Также, глядя на вашу реализацию конструктора класса Enemy, предполагая, что конструктор Character уже задает имя, здоровье и выносливость, вам не нужно устанавливать его снова в тело вашего Enemy конструктора (при условии, что у вас нет еще трех переменных, объявленных в вашем классе Enemy, которые называются name, health и stamina, что является недостатком дизайна, если вы это делаете).

Еще одна вещь, вы передаете переменную name по значению через конструктор Enemy. Чтобы предотвратить ненужное копирование и, следовательно, создать более эффективный код, передайте его по постоянной ссылке или std::move в конструктор Character, в зависимости от того, передает ли конструктор Character переменную имени по значению или нет. Это не обязательно для переменных работоспособности и выносливости, так как они тривиально копируемы и конструктивны для перемещения.

Подводя итог, если ваш конструктор Character объявлен так:

Character::Character(string name, int health, int stamina);

измените ваш Enemy конструктор на:

Enemy::Enemy(string name, int health, int stamina, bool _isEnemy, bool _roaming) : Character(std::move(name), health, stamina), isEnemy(_isEnemy), roaming(_romaing){
}

Это потребует от вас переместить аргумент имени в конструкторе Character в элемент имени класса Character, если это не так уже сделано.

РЕДАКТИРОВАТЬ:

Чтобы использовать наследование, вот как должны выглядеть класс Character и класс Enemy в отношении приведенных выше фрагментов кода:

//Character class 

class Character{
    private:
        //private data members
        std::string name;
        int health;
        int stamina;

    public:
        //constructor
        Character(const std::string& _name, int _health, int _stamina);

        //getters
        int get_health() const;
        int get_stamina();
        std::string get_name() const;

        //setters
        void set_health(int _health);
        void set_stamina(int _stamina);
        void set_name(const std::string& _name);
};

//Enemy class

//public inheritance from Character
class Enemy: public Character{
    private:
        //private data members
        bool isEnemy;
        bool roaming;

    public:
        //public constructor
        Enemy(const std::string& name, int health, int stamina, 
            bool _isEnemy, bool _roaming);
};

//Character class implementation

//set private data members in constructor
Character::Character(const std::string& _name, int _health, int _stamina)
          : name(_name), health(_health), stamina(_stamina){
}

//simple getter definitions 
int Character::get_health() const {
    return health;
}

int Character::get_stamina() const {
    return stamina;
}

std::string Character::get_name() const {
    return name;
}

//simple setters definitions
void Character::set_health(int _health) {
    health = _health;
}

void Character::set_stamina(int _stamina) {
    stamina = _stamina;
}

void Character::set_name(const std::string& _name) {
    name = _name;
}

//Enemy class implementation

//call character constructor, and set other private data members
Enemy(const std::string& name, int health, int stamina, 
        bool _isEnemy, bool _roaming) : Character(name, health, stamina),
        isEnemy(_isEnemy), roaming(_roaming){
}

Примечание. Возможно, вы захотите реализовать getters и setters для roaming и isEnemy в классе Enemy, аналогично getters и setters в классе Character ,

Обратите внимание, что имя, выносливость и здоровье не были повторно объявлены в классе врага. Это потому, что они уже существуют в классе Character, от которого наследует Enemy. Если вы хотите получить или установить имя, здоровье или выносливость, используйте publi c getter и setters из класса символов. Вы бы использовали их так:

Enemy dragonEnemy("Dragon", 100, 50, true, true);

//using public getter
int dragonHealth = dragonEnemy.get_health();

//using public setter
dragonEnemy.set_stamina(55);
...