Есть такая проблема: имеется иерархия классов. В производных появляются новые методы. Есть массив указателей на базовый класс. Когда я создаю экземпляр производного класса и обращаюсь к нему через указатель базового, он пытается найти метод в базовом классе, который не существует.
Люди добрые, помогите, пожалуйста. Я пытался делать понижающее преобразование типа указателя с помощью dynamic_cast:
MO[0] = dynamic_cast<hero*>(MO[0]);
Указатель вроде как меняет тип, но компилятор всё равно орёт
"[C++ Error] Main.cpp(230): E2316 'Move' is not a member of 'map_object'".
Вот важная часть кода:
class map_object {
int x,y, index;
public:
virtual void Draw()=0;
void set_x(int _x);
void set_y(int _y);
int get_x();
int get_y()y;
void set_index();
int get_index();
map_object(int _x, int _y);
};
map_object *MO[100];
class moving_object: public map_object {
public:
virtual void Move(int _d);
moving_object(int _x, int _y):map_object(_x, _y);
};
class creature: public moving_object {
int health;
void Death();
public:
void cure(int _health);
void damage(int _damage);
int get_health();
creature(int _x, int _y, int _health):moving_object(_x, _y);
};
class mage: public creature {
int mana;
public:
void mana_fill(int _mana);
void mana_reduce(int _mana);
int get_mana();
mage(int _x, int _y, int _health, int _mana):creature(_x, _y, _health);
};
class hero: public mage {
public:
void Draw();
hero(int _x, int _y, int _health, int _mana):mage(_x, _y, _health, _mana);
};
void __fastcall TfrmMain::FormKeyPress(TObject *Sender, char &Key) {
switch (Key) {
case 'w': {MO[0]->Move(0); break;}
case 'd': {MO[0]->Move(1); break;}
case 's': {MO[0]->Move(2); break;}
case 'a': {MO[0]->Move(3); break;}
}
}
Попробуйте посмотреть на ваш код глазами компилятора. Вы объявили MO как массив указателей на объекты класса map_object, в котором метода Move нет. Вы присвоили его элементам значения через dynamic_cast к hero - наследнику map_object. Чего вы этим добились? А ничего. MO как был массивом указателей на map_object, так им и остался. Компилятору, в общем-то, всё равно, каких наследников map_object'а вы присваиваете MO, при обращении по этому указателю он всегда будет видеть только те поля и методы, которые объявлены в map_object. Если вы хотите вызывать методы наследников по указателю на их предка, необходимо привести указатель на предка к указателю на наследника. Именно здесь и нужно* использовать понижающее преобразование:
dynamic_cast<hero*>(MO[0])->Move(0);
* На самом деле не нужно. Если ваша иерархия классов подразумевает принудительные понижающие преобразования, то скорее всего это плохая иерархия. В вашей иерархии теряется весь смысл наследования - вынесение общего для нескольких классов функционала в базовый класс и уменьшение свяности (coupling) вашего приложения. К тому же есть ненулевая вероятность, что однажды вы сделаете понижающее преобразование объекта из другой ветки иерархии, что приведёт к вылету программы.
Сборка персонального компьютера от Artline: умный выбор для современных пользователей