C++. Сборник рецептов - [115]

Шрифт
Интервал

Смотри также

Рецепт 8.7.

8.7. Определение, является ли класс объекта подклассом другого класса

Проблема

Имеется два объекта и требуется узнать, имеют ли их классы отношения на уровне базовый класс/производный класс, или они не связаны друг с другом.

Решение

Используйте оператор >dynamic_cast, который пытается выполнить преобразование одного типа в другой. Результат скажет, имеется ли связь между классами. Пример 8.7 представляет код, который это делает.

Пример 8.7. Определение отношений классов

>#include

>#include


>using namespace std;


>class Base {

>public:

> virtual ~Base() {} // Делаем класс полиморфным

>};


>class Derived : public Base {

>public:

> virtual ~Derived() {}

>};


>int main() {

> Derived d;

> // Запрашиваем тип отношений

> if (dynamic_cast(&d)) {

>  cout << "Derived является классом, производным от Base" << endl;

> } else {

>  cout << "Derived HE является классом, производным от Base" << endl;

> }

>}

Обсуждение

Для запроса отношений между двумя типами используйте оператор >dynamic_cast. >dynamic_cast принимает указатель или ссылку на некий тип и пытается преобразовать его к указателю или ссылке на производный класс, т.е. выполняя преобразование типа вниз по иерархии классов. Если есть >Base*, который указывает на объект >Derived, то >dynamic_cast(&d) возвращает указатель типа >Derived только в том случае, если >d — это объект типа, производного от >Base. Если преобразование невозможно (из-за того, что >Derived не является подклассом — явным или косвенным — класса >Base), то преобразование завершается неудачей и, если в >dynamic_cast был передан указатель на производный класс, возвращается >NULL. Если в него была передана ссылка, то выбрасывается стандартное исключение >bad_cast. Также базовый класс должен наследоваться как >public и это наследование не должно быть двусмысленным. Результат говорит о том, является ли один класс наследником другого класса. Вот что я сделал в примере 8.7.

>if (dynamic_cast(&d)) {

Здесь возвращается нe->NULL-указатель, так как >d — это объект класса, производного от >Base. Эту возможность можно использовать для определения отношения любых двух классов. Единственным требованием является то, что аргумент объекта должен быть полиморфным типом, что означает, что он должен иметь по крайней мере одну виртуальную функцию. Если это не будет соблюдено, то такой код не скомпилируется. Однако обычно это не вызывает особых проблем, так как иерархия классов без виртуальных функций встречается крайне редко.

Если этот синтаксис кажется вам слишком запутанным, используйте макрос, скрывающий некоторые подробности.

>#define IS_DERIVED_FROM(BaseClass, x) (dynamic_cast(&(x)))

>//...

>if (IS_DERIVED_FROM(Base, l)){//...

Но помните, что такая информация о типах не бесплатна, так как >dynamic_cast должен во время выполнения пройти по иерархии классов и определить, является ли один класс наследником другого, так что не злоупотребляйте этим способом. Кроме того, компиляторы не включают эту информацию по умолчанию, так как RTTI приводит к накладным расходам, и не все используют эту функцию, так что вам может потребоваться включить ее с помощью опции компилятора.

Смотри также

Рецепт 8.6.

8.8. Присвоение каждому экземпляру класса уникального идентификатора

Проблема

Требуется, чтобы каждый объект класса имел уникальный идентификатор.

Решение

Для отслеживания следующего доступного для использования идентификатора используйте статическую переменную-член. В конструкторе присвойте текущему объекту очередное доступное значение, а затем инкрементируйте статическую переменную. Чтобы понять, как это работает, посмотрите на пример 8.8.

Пример 8.8. Присвоение уникальных идентификаторов

>#include


>class UniqueID {

>protected:

> static int nextID;

>public:

> int id;

> UniqueID();

> UniqueID(const UniqueID& orig);

> UniqueID& operator=(const UniqueID& orig);

>};


>int UniqueID::nextID = 0;


>UniqueID::UniqueID() {

> id = ++nextID;

>}


>UniqueID::UniqueID(const UniqueID& orig) {

> id = orig.id;

>}


>UniqueID& UniqueID::operator=(const UniqueID& orig) {

> id = orig.id;

> return(*this);

>}


>int main() {

> UniqueID a;

> std::cout << a.id << std::endl;

> UniqueID b;

> std::cout << b.id << std::endl;

> UniqueID c;

> std::cout << c.id << std::endl;

>}

Обсуждение

Для отслеживания следующего доступного для использования идентификатора используйте статическую переменную. В примере 8.8 используется >static int, но вместо нее можно использовать все, что угодно, при условии, что имеется функция, которая может генерировать уникальные значения.

В данном случае идентификаторы не используются повторно до тех пор, пока не будет достигнуто максимально возможное для целого числа значение. При удалении объекта его уникальное значение пропадает либо до перезапуска программы, либо до переполнения значения идентификатора. Эта уникальность в программе может иметь несколько интересных преимуществ. Например, при работе с библиотекой управления памятью, которая перемещает блоки памяти и обновляет значения указателей, можно быть уверенным, что для каждого объекта будет сохранено его первоначальное уникальное значение. При использовании уникальных значений в сочетании с рецептом 8.4, но применении


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Создаем порт для FreeBSD своими руками. Часть II

Система сборки программ, используемая во FreeBSD, имеет значительно большие возможности, чем те, которые мы задействовали. Какие это возможности и как их использовать в своих портах?


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.