Чтение онлайн

на главную - закладки

Жанры

C++. Сборник рецептов

Когсуэлл Джефф

Шрифт:

Это позволяет явно проверять определенный тип.

Вероятно, наиболее часто

typeid
используется для отладки. Для записи имени типа используйте
type_info::name
, как здесь.

std::cout << typeid(d).name << std::endl;

При передаче объектов различных типов это может быть очень полезно. Строка, завершающаяся нулем, возвращаемая

name
, зависит от реализации, но вы можете ожидать (но не полагаться на это), что она будет равна имени типа. Это также работает и для встроенных типов.

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

выполняет что-то похожее на следующее, расценивается как плохой дизайн.

Если

obj
имеет тип
X
, сделать что-то одно, а если
obj
имеет тип
Y
, сделать что-то другое.

Это плохой дизайн, потому что клиентский код теперь содержит избыточные зависимости от типов используемых объектов. Это также приводит к большой каше из if/then кода, который то и дело повторяется, если для объектов типов

X
или
Y
требуется различное поведение. Объектно-ориентированное программирование и полиморфизм существуют в большой степени для того, чтобы избавить нас от написания подобного рода логики. Если для какого-либо семейства связанных классов требуется зависящее от типа поведение, то они все должны наследоваться от какого-то базового класса и использовать виртуальные функции, динамически вызывая различное поведение в зависимости от типа.

RTTI приводит к накладным расходам, так что компиляторы обычно по умолчанию его отключают. Скорее всего ваш компилятор имеет параметр командной строки для включения RTTI. Также это не единственный способ, которым можно получить информацию о типе. Другая методика приведена в рецепте 8.7.

Смотри также

Рецепт 8.7.

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

Проблема

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

Решение

Используйте оператор

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

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

#include <iostream>

#include <typeinfo>

using namespace std;

class Base {

public:

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

};

class Derived : public Base {

public:

 virtual ~Derived {}

};

int main {

 Derived d;

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

 if (dynamic_cast<Base*>(&d)) {

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

 } else {

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

 }

}

Обсуждение

Для запроса отношений между двумя типами используйте оператор

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

if (dynamic_cast<Base*>(&d)) {

Здесь возвращается нe-

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

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

#define IS_DERIVED_FROM(BaseClass, x) (dynamic_cast<baseClass*>(&(x)))

//...

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

Но помните, что такая информация о типах не бесплатна, так как

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

Смотри также

Рецепт 8.6.

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

Проблема

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

Решение

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

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

#include <iostream>

class UniqueID {

protected:

 static int nextID;

public:

 int id;

 UniqueID;

 UniqueID(const UniqueID& orig);

 UniqueID& operator=(const UniqueID& orig);

};

int UniqueID::nextID = 0;

Поделиться:
Популярные книги

Наследник чародея. Школяр. Книга первая

Рюмин Сергей
1. Наследник чародея
Фантастика:
городское фэнтези
5.00
рейтинг книги
Наследник чародея. Школяр. Книга первая

Проданная невеста

Wolf Lita
Любовные романы:
любовно-фантастические романы
5.80
рейтинг книги
Проданная невеста

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Черт из табакерки

Донцова Дарья
1. Виола Тараканова. В мире преступных страстей
Детективы:
иронические детективы
8.37
рейтинг книги
Черт из табакерки

Новый Рал 9

Северный Лис
9. Рал!
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Новый Рал 9

Росток

Ланцов Михаил Алексеевич
2. Хозяин дубравы
Фантастика:
попаданцы
альтернативная история
фэнтези
7.00
рейтинг книги
Росток

Пять попыток вспомнить правду

Муратова Ульяна
2. Проклятые луной
Фантастика:
фэнтези
эпическая фантастика
5.00
рейтинг книги
Пять попыток вспомнить правду

Александр Агренев. Трилогия

Кулаков Алексей Иванович
Александр Агренев
Фантастика:
альтернативная история
9.17
рейтинг книги
Александр Агренев. Трилогия

Наследник с Меткой Охотника

Тарс Элиан
1. Десять Принцев Российской Империи
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Наследник с Меткой Охотника

Хозяйка старой пасеки

Шнейдер Наталья
Фантастика:
попаданцы
фэнтези
7.50
рейтинг книги
Хозяйка старой пасеки

Выйду замуж за спасателя

Рам Янка
1. Спасатели
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Выйду замуж за спасателя

Искатель 2

Шиленко Сергей
2. Валинор
Фантастика:
фэнтези
попаданцы
рпг
5.00
рейтинг книги
Искатель 2

Мастер Разума III

Кронос Александр
3. Мастер Разума
Фантастика:
героическая фантастика
попаданцы
аниме
5.25
рейтинг книги
Мастер Разума III

Родословная. Том 2

Ткачев Андрей Юрьевич
2. Линия крови
Фантастика:
городское фэнтези
аниме
фэнтези
5.00
рейтинг книги
Родословная. Том 2