Навигация
Главная
Поиск
Форум
FAQ's
Ссылки
Карта сайта
Чат программистов

Статьи
-Delphi
-C/C++
-Turbo Pascal
-Assembler
-Java/JS
-PHP
-Perl
-DHTML
-Prolog
-GPSS
-Сайтостроительство
-CMS: PHP Fusion
-Инвестирование

Файлы
-Для программистов
-Компонеты для Delphi
-Исходники на Delphi
-Исходники на C/C++
-Книги по Delphi
-Книги по С/С++
-Книги по JAVA/JS
-Книги по Basic/VB/.NET
-Книги по PHP/MySQL
-Книги по Assembler
-PHP Fusion MOD'ы
-by Kest
Professional Download System
Реклама
Услуги

Автоматическое добавление статей на сайты на Wordpress, Joomla, DLE
Заказать продвижение сайта
Программа для рисования блок-схем
Инженерный калькулятор онлайн
Таблица сложения онлайн
Популярные статьи
OpenGL и Delphi... 65535
Форум на вашем ... 65535
21 ошибка прогр... 65535
HACK F.A.Q 65535
Бип из системно... 65535
Гостевая книга ... 65535
Invision Power ... 65535
Пример работы с... 65535
Содержание сайт... 65535
ТЕХНОЛОГИИ ДОСТ... 65535
Организация зап... 65535
Вызов хранимых ... 65535
Создание отчето... 65535
Имитационное мо... 65535
Программируемая... 65535
Эмулятор микроп... 65535
Подключение Mic... 65535
Создание потоко... 65535
Приложение «Про... 65535
Оператор выбора... 65535
Реклама
Сейчас на сайте
Гостей: 7
На сайте нет зарегистрированных пользователей

Пользователей: 13,363
новичок: xopumun11
Новости
Реклама
Выполняем курсовые и лабораторные по разным языкам программирования
Подробнее - курсовые и лабораторные на заказ
Delphi, Turbo Pascal, Assembler, C, C++, C#, Visual Basic, Java, GPSS, Prolog, 3D MAX, Компас 3D
Заказать программу для Windows Mobile, Symbian

Моделирование работы класса персональных компьютеров на GPSS + Отчет + Б...
Метод конечных разностей для интерполяции/экстраполяции на Delphi
Расчет обратной матрицы на Delphi + Пояснительная записка

Сам механизм RTTI не является особенно сложным
Сам механизм RTTI не является особенно сложным, однако не всегда понятно, когда и как его нужно применять, поскольку виртуальные функции позволяют в большинстве случаев обойтись без RTTI.
1 Реальным примером такой системы является Windows.
Рассмотрим пример. Предположим, мы разрабатываем файловую систему в составе некоей операционной системы с интерфейсом GUI1 [55, 56, 59]. Для пользователя файлы представляются пиктограммами. Щелкнув на пиктограмме правой кнопкой мыши, мы получаем контекстное меню с командами открытия, закрытия, копирования и т. п. Реализация файловой системы основана на иерархии классов, корнем которой является абстрактный класс File примерно следующего вида:


rtual void open() = 0;
rtual void closeQ = 0;
rtual void read() = 0;
rtual void write() = 0;
virtual ~File() = 0;
};
File::~File(){} // чистый виртуальный деструктор требует реализации



Пусть в системе в первой версии существуют текстовые файлы и двоичные исполняемые файлы. В иерархии классов эти файлы представлены классами-наследниками от базового абстрактного класса, в которых реализованы чистые виртуальные функции. Например, класс BinaryFile определяет двоичный исполняемый файл:
class BinaryFile: public File { public:
void open() { Execute(this); }
// другие методы
};
Класс TextFi le определяет тестовый файл:
class TextFile: public File { public:
void open() { Activate_text_processor(this); } virtual void printO; // другие методы
};



Двоичные файлы, естественно, отличаются от текстовых во многих деталях. Например, при открытии двоичного файла он запускается на выполнение, а при открытии текстового файла запускается текстовый редактор и ему передается текущий открываемый файл. Поскольку у нас функции открытия виртуальные, то проблем с правильным открытием не должно возникать. Однако различие проявляется и в том, что текстовые файлы можно печатать, а двоичные — нет. Следовательно, в классе TextFile существует специфический для этого типа файлов метод printO, которого нет в классе BinaryFile.
Щелчок правой кнопкой мыши на пиктограмме файла должна обрабатывать API-функция, которая открывает упомянутое контекстное меню. Заголовок функции может выглядеть так:
OnRightClick(File &file);



Функция принимает параметр базового класса, следовательно, в соответствии с принципом подстановки, может принимать в качестве аргумента как текстовый, так и двоичный файлы. Однако наши файлы не одинаковы: контекстное меню текстового файла должно отличаться от контекстного меню двоичного файла, по крайней мере, наличием команды печати. Следовательно, функция
OnRightClickO должна «уметь» различать типы файлов во время работы! Это можно обеспечить с помощью оператора typeidO. Структура функции может быть такой:
OnRightClick(File &file)
{ if (typeid(file) == typeid(TextFile))
{ // обработка текстового файла
}
else
{ // обработка двоичного файла }
}



Хотя статическим типом аргумента file является тип File, на место объекта базового класса может быть подставлен объект производного класса. Поэтому оператор typeidO возвращает объект type_info, который несет информацию о реальном типе передаваемого аргумента. Оператор i f проверяет, совпадает ли реальный тип аргумента f i le с типом TextFi le.
Однако одного оператора typeid () может оказаться недостаточно. Пусть у нас в системе появляется третий тип файла: HTML-файл. Так как HTML-файл является текстовым файлом, то, естественно, класс HTMLFile является наследником класса TextFile:
class HTMLFile: public TextFile { public:
void open() { Activate_Brouser(this); } vi rtual void printO ; // другие методы
};



Реализация функции открытия, естественно, отличается от реализации функции открытия базового текстового файла: для HTML-файла вызывается программа-браузер1. Функция печати, очевидно, тоже должна быть реализована по-другому.
В функции OnRi ghtCl i ck () у нас возникают проблемы, так как при передаче аргумента типа HTMLFi le она будет работать по ветке двоичного файла. А все потому, что значение typeid(HTMLFi le) не равно значению typeid(TextFile), хотя типы HTMLFi le и TextFi le — ближайшие «родственники». В такой ситуации нам и может пригодиться оператор dynamic__cast<>. Вместо ссылки будем передавать в функцию OnRightClickO указатель. Тогда функция приобретает следующий вид:
OnRightClick(File *file)
{ TextFile *pFile = dynamic_cast<TextFile *>(file); if (pFile)
{ // обработка текстового файпа и HTML-файла }
else
{ // обработка двоичного файла }



1 Не забывайте, что в базовом абстрактном классе функция открытия определена как чистая виртуальная, поэтому во всех производных классах она тоже является виртуальной, хотя это явно и не указано.
Если в функцию будет передан указатель на HTMLFi 1е, то он успешно преобразуется к типу указателя на TextFi 1е. В этом случае указатель pFi le оказывается ненулевым. Если же при вызове функции будет передаваться аргумент-указатель на двоичный файл, то преобразование не выполнится и указатель pFile станет нулевым.
Немного другой вид функция приобретает при передаче параметра-ссылки:
OnRightClick(File &file) { try {
TextFile pFile = dynamic_cast<TextFile &>(file); , // обработка текстового файла и HTML-файла
}
catch(std::bad_cast &noTextFile) { // обработка двоичного файла }
}



Если преобразование ссылки обошлось без генерации исключения, значит, имеем в наличии текстовый файл. Если же ссылку преобразовать не удалось, то файл, очевидно, не является текстовым — возникает исключение, и мы его перехватываем. В секции-ловушке выполняется обработка двоичного файла.
Перекрестные ссылки можно делать, например, так:
struct А { double d:
virtual ~А(){}; // чтобы сделать класс полиморфным
>:
struct В { double г: bool b:
};
struct D: public A, public B { int k;
D() { b=true: d=r=0.0; k=l; }
};
A *pa = new D();
B *pb = dynamic_cast<B*>(pa);



Статический тип pa — указатель на А, динамический — указатель на D. Обычный static_cast<> не может преобразовать указатель на А в указатель на В, так как классы А и В независимы. Можно использовать оператор reinterpret_cast<> или преобразование в стиле С (В*) — трансляция пройдет без ошибок, однако результаты работы будут неправильными. В этом легко убедиться, если выполнить простой оператор вывода:
cout << pb->b << endl:
Так как поле b в конструкторе D() инициализируется как true, на экране должна появиться цифра 1. Однако при использовании оператора reinterpret_cast<> выводится нуль. В то же время при использовании оператора dynamic_cast<> все работает правильно. В этой проблеме легко разобраться, если проверить значения указателей в том и другом случаях: при использовании оператора reinterpret_cast<> адреса, содержащиеся в ра и pb, одинаковы, а при использовании оператора dynamic_cast<> — разные. Это объясняется тем, что в объекте типа D объекты типа А и В занимают разные места. Оператор dynamic_ cast<> правильно вычисляет адрес подобъекта типа В внутри D, а оператор reinterpret_cast<> этого не делает.
Понижающее приведение с помощью оператора dynamic_cast<> выполняется обычно, чтобы преобразовать указатель на виртуальную базу в указатель на один из дочерних классов, например:
struct V
{ virtual ~V() {}: // полиморфный класс - виртуальная база
}:
struct A: virtual V {}; struct В: virtual V {}; struct D: public A. public В {}; V *pv = new D;
A *pa = dynamic__cast<A*>(pv); // понижающее приведение



Программистам приходится часто налаживать сеть. Для этого нужны кабели. Сэкономить можно тут купить кабель оптом .

Указатель pv имеет статический тип V, а указатель ра — статический тип А; преобразование выполняется от базы к наследнику. Это возможно вследствие того, что динамический тип указателя pv — тип D, а значит, в динамике выполняется повышающее приведение от D к А.
Опубликовал Kest December 03 2013 01:16:08 · 1 Комментариев · 2900 Прочтений · Для печати

• Не нашли ответ на свой вопрос? Тогда задайте вопрос в комментариях или на форуме! •


Комментарии
Степан January 26 2014 17:25:43
Действительно программа весьма сложная, но разобраться в ней можно, если подольше посидеть. К тому же она несомненно является нужной для людей разрабатывающих файловую систему. Так как программистам в большинстве случаев приходится постоянно налаживать кабельную сеть для непрерывной работы в системе.
Добавить комментарий
Имя:



smiley smiley smiley smiley smiley smiley smiley smiley smiley
Запретить смайлики в комментариях

Введите проверочный код:* =
Рейтинги
Рейтинг доступен только для пользователей.

Пожалуйста, залогиньтесь или зарегистрируйтесь для голосования.

Нет данных для оценки.
Гость
Имя

Пароль



Вы не зарегистрированны?
Нажмите здесь для регистрации.

Забыли пароль?
Запросите новый здесь.
Поделиться ссылкой
Фолловь меня в Твиттере! • Смотрите канал о путешествияхКак приготовить мидии в тайланде?
Загрузки
Новые загрузки
iChat v.7.0 Final...
iComm v.6.1 - выв...
Visual Studio 200...
CodeGear RAD Stud...
Шаблон для новост...

Случайные загрузки
ZipForge
Программирование ...
mp3tag
Tank [Исходник на...
Игра "Астероиды" ...
AddPage [Исходник...
База для Allsubmi...
База данных фильм...
Borland Delphi 6....
PHP 5. Практика с...
MiniChat
IpEditAdress
БД студентов
Java Server Pages...
Книга по Delphi (...
Краснов М. - Open...
Пример клиента ФТ...
iComm v.6.1 - выв...
Длинный заголовок...
В.Понамарев - COM...

Топ загрузок
Приложение Клие... 100774
Delphi 7 Enterp... 97832
Converter AMR<-... 20268
GPSS World Stud... 17014
Borland C++Buil... 14191
Borland Delphi ... 10290
Turbo Pascal fo... 7373
Калькулятор [Ис... 5984
Visual Studio 2... 5207
Microsoft SQL S... 3661
Случайные статьи
Кодирование
Подвесной светильн...
Планирование
Работа с нижней по...
ЭТАП 3. ВЫЯСНЕНИЕ ...
Планируемые характ...
Какие есть адреса ...
Конфигурируя бранд...
Инициализация данн...
1.2. ЧТО СОДЕРЖИТС...
Регистрация ActiveX
Модуль CRT. Раблта...
7.5. Обработка с...
Методика проектиро...
Технология FTTH
Game Boy, 1989 год
Типизированные файлы
Где мы находимся?
Методы класса
Перспективы свопинга
Персептрону. Пробл...
Error in real cons...
СПОСОБЫ РАСПОЗНАВА...
Создание иконки пр...
Ликбез по meta-тег...
Статистика



Друзья сайта
Программы, игры


Полезно
В какую объединенную сеть входит классовая сеть? Суммирование маршрутов Занимают ли таблицы память маршрутизатора?