|
Программирование >> Разработка устойчивых систем
Компилятор знает, что такое преобразование всегда является нежелательным, и поэтому требует использовать оператор dynamic cast. Области применения RTTI Новички часто злоупотребляют возможностью получения информации типа по анонимному полиморфному указателю, потому что обычно они понимают логику работы RTTI раньше, чем логику работы механизма виртуальных функций. Многим программистам с опытом процедурного программирования нелегко избавиться от привычки делить программу на команды switch. RTTI позволяет реализовать такую логику, однако при этом теряются важные преимущества полиморфизма в разработке и сопровождении программ. Язык С++ проектировался с расчетом на то, что программист будет использовать виртуальные функции и прибегнет к RTTI только в случае необходимости. Тем не менее, предполагаемое использование виртуальных функций требует наличия определения базового класса, поскольку на некоторой стадии расширения программы может оказаться, что базовый класс не содержит необходимых виртуальных функций. Если базовый класс взят из библиотеки или по другим причинам неподконтролен вам, единственным решением остается RTTI. Вы определяете новый тип и включаете в него дополнительные функции, а затем в другой точке программы выявляете этот конкретный тип и вызываете функцию. Полиморфизм и расширяемость программы при этом не страдают, поскольку добавление нового типа не требует массового перехода на логику switch. Тем не менее при включении в основную программу новых фрагментов, опирающихся на новые возможности, необходимо организовать идентификацию нового типа. Расширение базового icTiacca может привести к тому, что ради удобства одного конкретного класса во все остальные icTiaccbi, производные от общей базы, придется включать какую-нибудь бессмысленную заглушку для чисто виртуальной функции. В результате интерфейс становится менее понятным и раздражает тех, кто должен переопределять чисто виртуальные функции при наследовании от этого базового класса. Наконец, RTTI иногда помогает решить проблемы эффеетивности. Если программа использует полиморфизм так, как положено, но какой-нибудь объект реагирует на обобщенный код крайне неэффективно, можно идентифицировать этот тип средствами RTTI и написать специализированный код для повышения эффективности. Пример Следующий пример, демонстрирующий практическое применение RTTI, имитирует систему переработки мусора. Различные виды мусора попадают в общий контейнер, а затем сортируются в соответствии со своими динамическими типами. : C08:Trash.h Описания разных видов мусора #ifndef TRASH H #define TRASH H linclude <iostream> class Trash { float we1ght: public: Trash(float wt) : we1ght(wt) {} virtual float valueO const - 0: float weightO const { return weight: } virtual -TrashO { std::cout -Trash() std::endl: class Aluminum : public Trash { static float val: public: Aluminum(float wt) : Trash(wt) {} float valueO const { return val: } static void value(float newval) { val - newval: class Paper : public Trash { static float val: public: PaperCfloat wt) : Trash(wt) {} float valueO const { return val: } static void value(float newval) { val - newval: class Glass : public Trash { static float val: public: Glass(float wt) : Trash(wt) {} float valueO const { return val: } static void valueCfloat newval) { val = newval: #endif TRASH H III:- Статические значения, определяющие стоимость единицы вторсырья , определяются в файле реализации: : C08:Trash.cpp {0} Переработка мусора #include Trash.h float Aluminum::val = 1.67: float Paper::val = 0.10: float Glass::val - 0.23: III:- Шаблон sumValue() перебирает содержимое контейнера, вычисляет суммарную стоимость по разным видам мусора и отображает результаты: : СОВ:Recycle.срр {L} Trash Переработка мусора #i nclude <cstdlib> #include <ctime> #include <iostream> #include <typeinfo> #include <vector> #include Trash.h #1nc1ude ../purge.h using namespace std; Вычисление суммарной стоимости одного вида мусора: tempiate<class Container> void sumValue(Container& bin. ostream& os) { typename Container: :iterator tally = bin.beginO: float val =0: whileCtally != bin.endO) { val += (*tally)->weight() * (*tally)->value(): OS weight of typeid(**tally).name() = (*tally)->weight() endl: ++tally: OS Total value = val endl: int mainO { srand(time(0)): Раскрутка генератора случайных чисел vector<Trash*> bin: Заполнение контейнера объектами Trash: for(int i = 0: i < 30: i++) switchCrandO % 3) { case 0 : bin.push back(new Aluminum((rand() % 1000)/10.0)): break: case 1 : bin.push back(new Paper((rand() % 1000)/10.0)): break: case 2 : bin.push back(new Glass((rand() % 1000)/10.0)): break: Внимание: в специализированных мусорных баках хранятся фактические типы, а не базовый тип: vector<Glass*> glassBin: vector<Paper*> paperBin: vector<Aluminum*> alumBin: vector<Trash*>::iterator sorter = bin.beginO: Сортировка мусора: while(sorter != bin.endO) { Aluminum* ap = dynami c cast<Alumi num*>(*sorter): Paper* pp = dynamic cast<Paper*>(*sorter); Glass* gp = dynamic cast<Glass*>(*sorter): if(ap) alumBin.push back(ap): else if(pp) paperBin.push back(pp): else if(gp) glassBin.push back(gp): ++sorter: sumValueCalumBin. cout): sumValue(paperBin. cout):
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |