Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP_otvety_k_ekzamenu.doc
Скачиваний:
55
Добавлен:
13.04.2015
Размер:
786.94 Кб
Скачать

41. Альтернативные решения, заменяющие dynamic_cast. Виртуальные функции для понижающего преобразования. Типовое решение Visitor.

Альтернативные решения, заменяющие dynamic_cast. Виртуальные функции для понижающего преобразования. Типовое решение Visitor.

Простейшее решение, показанное ниже, работает в среднем от 2 до 7 раз быстрее типичной реализации оператора dynamic_cast, однако требует заметного объема дополнительных ручных действий со стороны программиста. В базовом классе следует определить по одному виртуальному методу преобразования к каждому конкретному классу иерархии. В базовом классе эти функции всегда должны возвращать значение nullptr:

class FilesystemEntry

{

// ...

public:

// ...

virtual File * asFile () { return nullptr; }

virtual Directory * asDirectory () { return nullptr; }

};

В каждом конкретном производном классе иерархии следует переопределить один из этих методов преобразования, соответствующий классу. Файл будет переопределять метод преобразования в файл, а каталог - в каталог:

class File : public FilesystemEntry

{

// ...

public:

// ...

File * asFile () override { return this; }

};

class Directory : public FilesystemEntry

{

// ...

public:

// ...

Directory * asDirectory () override { return this; }

};

Теперь можно воспользоваться этими методами вместо оператора dynamic_cast:

FilesystemEntry * pEntry = new File( “1.txt”, 50 );

File * pFile = pEntry->asFile();

assert( pFile );

При добавлении нового класса в иерархию (например, SymbolicLink - символическая ссылка), будет нужно добавить к базовому классу FilesystemEntry еще один метод преобразования для нового конкретного класса.

Лучшую гибкость обеспечивает типовое решение Visitor (посетитель), при этом не засоряя иерархию прикладными функциями. Оригинальную иерархию дополняют таким необычным интерфейсом, в котором имеется по одной чисто виртуальной функции visit, принимающей в качестве единственного аргумента ссылку на один из конкретных классов иерархии.В базовом классе следует ввести одну дополнительную операцию - прием посетителя - в виде чисто виртуальной функции.

Любой конкретный производный класс будет обязан переопределить эту функцию приема, при этом реализация всего лишь будет перенаправлять вызов к соответствующему методу класса-посетителя. Конкретный метод будет выбираться исходя из текущего класса, руководствуясь обычными правилами разрешения перегрузки:

Такой подход имеет ряд преимуществ:

· получена функционально идентичная реализация, в которой нет ни одного оператора преобразования типа вниз по иерархии;

· классы предметной области (FilesystemEntry, File, Directory) не засорены конкретными элементами реализации прикладного характера;

· если потребуется другая прикладная функциональность, будет достаточно определить еще одну реализацию интерфейса-посетителя в подобном стиле;

· при расширении иерархии модели новым классом, например, SymbolicLink, не удастся забыть добавить реализацию обработки таких объектов, поскольку благодаря комбинации чисто виртуальных функций accept/visit не удастся скомпилировать проект:

o без реализации метода accept нельзя будет создать объект SymbolicLink;

o решение этой проблемы потребует добавления нового метода visit в интерфейс посетителя;

o без добавления реализации этого нового метода не будет возможности создать ни один из объектов конкретного класса-посетителя;

Таким образом, обеспечивается логичное разделение обязанностей между различными частями программы с автоматически контролируемым компилятором расширением иерархии без внесения трудно уловимых ошибок.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]