6. Полиморфизм.
«Объектно-ориентированное программирование»
доцентПриваловМ.В.
Донецк,ДонНТУ,2011
Пример.
class employee { char* name; employee* next; // ...
public:
void print() const;
};
class manager : public employee { // ...
public:
void print() const;
};
Пример.
//Вариант 1.
//Печать общей информации void manager::print() const {
cout << " имя " << name << '\n';
}
//Вариант 2.
//Печать информации о сотруднике и о менеджере отдельно
void manager::print() const {
//печать данных о служащих employee::print();
//печать данных об управляющих
}
КАКОТЛИЧИТЬ КЛАССЫСОТРУДНИКАИМЕНЕДЖЕРА?
Способыразличенияобъектов классовиерархии
Операторtypeid
Полятипа
Аможнонезаниматьсявприкладном программномкоденахождением "истинного"типаобъекта,а задействоватьполиморфизм.
Динамическаяидентификация типовспомощьюtypeid
Динамическаяидентификациятипов
(RTTI - Run Time Type Identification)-
этоопределениетипаобъектаво времявыполненияпрограммы
ДляэтоговC++ есть
Операторtypeid
Класс type_info
Динамическаяидентификация
типовспомощьюtypeid
#include "stdafx.h" #include <iostream> #include <typeinfo> using namespace std;
class employee {};
class manager : public employee {};
int _tmain(int argc, _TCHAR* argv[]) { employee e, *ePtr = new employee(), *staff[2];
manager m, *mPtr = new manager(); staff[0] = ePtr;
staff[1] = mPtr;
Динамическаяидентификация
типовспомощьюtypeid
cout << "e id = " << typeid(e).name() << endl;
cout << "ePtr id = " << typeid(ePtr).name() << endl;
cout << "m id = " << typeid(m).name() << endl;
cout << "mPtr id = " << typeid(mPtr).name() << endl;
cout << "staff[0] id = " << typeid(*staff[0]).name() << endl;
cout << "staff[1] id = " << typeid(*staff[1]).name() << endl;
cin.ignore(); return 0;
}
Динамическаяидентификация
типовспомощьюtypeid
e id = class employee ePtr id = class employee * m id = class manager
mPtr id = class manager * staff[0] id = class employee staff[1] id = class employee
Динамическаяидентификация типовспомощьюtypeid
Оператор typeid можетопределить типобъектавовремявыполнения программы,однакоониспользует тоттипсвязывания,который задействованприсоздании иерархии.
Безполиморфизмаtypeid нерешает проблему!
Полятипа.
Полетипаэтоатрибуткласса, позволяющийузнатьеготип
class employee {
enum empl_type { M, E }; protected:
empl_type type; //..
friend void print_employee (const employee *e);
};
Полятипа.
//Попыткасоздания универсальной
//функциидляпечатисотрудников
void print_employee(const employee *e) { switch (e->type) {
case E:
// Печатаемсотрудника case M:
//Печатаемменеджера
}
}
Чтотакоераннееипозднее связывание?
Раннеесвязывание(static/early biding)-
этоопределениеадресовметодовна этапекомпиляции.
Раннеесвязываниеиспользуетсяпри вызовеобычныхиперегруженных функций,приработесобъектами классов.
Примерраннегосвязывания
#include <iostream> #include <cstdlib>
using namespace std;
class Performer { private:
char name[30]; public:
Performer(const char * name)
{ strcpy(this->name, name); }
void perform() {
printf("%-15s - Владимирский централ...\n", getName()); }
const char * getName() const { return name; }
};
Примерраннегосвязывания
class Singer : public Performer { public:
Singer(const char* name): Performer(name) {}
void perform() { printf(
"%-15s - This desert rose each of "
"her veils, a secret promise\n", getName()); }
};
Примерраннегосвязывания
class Dj : public Performer { private:
void umz() { printf("Умц! "); } public:
Dj(const char* name):Performer(name) {} void perform();
};
void Dj::perform() { printf("%-15s - ", getName()); for (int i=0; i<10; i++)
umz();
printf("\n");
}
Примерраннегосвязывания
class CircusArtist : public Performer { public:
CircusArtist(const char* name) : Performer(name) {}
void perform()
{
printf("%-15s - Алеее.. Гоп!\n", getName()); }
};
Примерраннегосвязывания
int main(int argc, char *argv[]) { Performer * performers[3] = {
new Singer("Sting"), new Dj("Plasma"),
new CircusArtist("Kuklachev") };
for (int i=0; i<3; i++) performers[i]->perform();
return 0;
}