какой оператор следует использовать для определения типа объекта во время работы программы

Прочитайте онлайн C++. Сборник рецептов | 8.6. Определение типа объекта во время выполнения

8.6. Определение типа объекта во время выполнения

Во время выполнения требуется динамически узнавать тип определенного класса.

Для запроса, на объект какого типа указывает адрес объекта, используйте идентификацию типов во время выполнения (обычно называемую просто RTTI — runtime type identification). Пример 8.6 показывает, как это делается.

Пример 8.6. Использование идентификации типов во время выполнения

using namespace std;

class Derived : public Base <>;

// Используем typeid для проверки равенства типов

if (typeid(b) == typeid(d)) < // No

if (typeid(b) == typeid(bb)) < // Yes

it (typeid(a) == typeid(Derived)) < // Yes

Пример 8.6 показывает, как использовать оператор typeid для определения и сравнения типов объектов, typeid принимает выражение или тип и возвращает ссылку на объект типа type_info или его подкласс (что зависит от реализации). Возвращенное значение можно использовать для проверки на равенство или получить строковое представление имени типа. Например, сравнить типы двух объектов можно так.

if (typeid(b) == typeid(d)) <

Это выражение возвращает истину, если возвращаемые объекты type_info равны. Это работает благодаря тому, что typeid возвращает ссылку на статический объект, так что при его вызове для двух объектов одного и того же типа будут получены две ссылки на один и тот же объект и сравнение вернет истину.

typeid также можно использовать непосредственно с типом, как здесь.

if (typeid(d) == typeid(Derived)) <

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

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

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

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

Источник

Динамическая идентификация типа данных

Динамическая идентификация типа данных (англ. Run-time type information, Run-time type identification, RTTI ) — механизм в некоторых языках программирования, который позволяет определить тип данных переменной или объекта во время выполнения программы.

Содержание

Реализация

Существует множество реализаций такого механизма, но наиболее распространенными являются:

В C++ для динамической идентификации типов [1] применяются операторы dynamic_cast и typeid (определён в файле typeinfo.h), для использования которых информацию о типах во время выполнения обычно необходимо добавить через опции компилятора при компиляции модуля.

Delphi

Компилятор Delphi сохраняет в исполняемом файле программы информацию обо всех классах, используемых в ней. При создании любого объекта в памяти перед ним (по отрицательным смещениям) располагается заголовок, в котором есть в том числе ссылка на структуру-описатель класса этого объекта. Встроенные в язык функции работают с этой информацией прозрачно для программиста. Оператор is позволяет проверить, является ли объект или тип наследником определённого типа, а оператор as является аналогом dynamic_cast в C++.

Заголовки объектов — также неявно — используются для автоматического управления памятью.

На уровне байт-кода вызов метода класс записывается, как и вызов всякого другого метода, при помощи опкода invokevirtual. Для проверки приводимости объекта к типу используются опкоды instanceof и checkcast.

В Perl тип объекта может быть определен с помощью функции blessed(), являющуюся частью CPAN-модуля Scalar::Util. Функция принимает указатель на объект (blessed hash или аналог) и возвращает скаляр, содержащий имя класса.

Источник

8.6. Определение типа объекта во время выполнения

8.6. Определение типа объекта во время выполнения

Во время выполнения требуется динамически узнавать тип определенного класса.

Для запроса, на объект какого типа указывает адрес объекта, используйте идентификацию типов во время выполнения (обычно называемую просто RTTI — runtime type identification). Пример 8.6 показывает, как это делается.

Пример 8.6. Использование идентификации типов во время выполнения

using namespace std;

class Derived : public Base <>;

// Используем typeid для проверки равенства типов

if (typeid(b) == typeid(d)) < // No

Читайте также

Глава 27 Динамическая загрузка во время выполнения

Глава 27 Динамическая загрузка во время выполнения Загрузка разделяемых (совместно используемых) объектов во время выполнения может оказаться полезным способом для структурирования собственных приложений. Если правильно организовать этот процесс, то тогда можно будет

Практическое определение объекта

Определение объекта Range

Определение объекта Range В Excel имеется несколько возможных методов идентификации диапазона из одной или нескольких ячеек, на который должен воздействовать написанный код. Для достижения данной цели используются следующие.Стандартная ссылка на ячейку. Так называемый

15.8.2. Emacs и отладка во время выполнения

15.8.2. Emacs и отладка во время выполнения Для обнаружения ошибок времени выполнения Emacs предоставляет аналогичную возможность интеграции с символическим отладчиком, т.е. разработчик может использовать какой-либо Emacs-режим для установки контрольных точек в программах и

15.8.2. Emacs и отладка во время выполнения

15.8.2. Emacs и отладка во время выполнения Для обнаружения ошибок времени выполнения Emacs предоставляет аналогичную возможность интеграции с символическим отладчиком, т.е. разработчик может использовать какой-либо Emacs-режим для установки контрольных точек в программах и

1.4.1. Кодирование во время выполнения

1.4.1. Кодирование во время выполнения Мы уже упоминали директивы load и require. Важно понимать, что это не встроенные предложения и не управляющие конструкции; на самом деле это методы. Поэтому их можно вызывать, передавая переменные или выражения как параметры, в том числе

Определение «объекта приложения»

Определение «объекта приложения» В настоящее время тип HelloClass решает две задачи. Во-первых, этот класс определяет точку входа в приложение (метод Main()). Во-вторых, HelloClass поддерживает элемент данных и несколько конструкторов. Все это хорошо и синтаксически правильно, но

6.12.1. Определение объекта map и заполнение его элементами

6.12.1. Определение объекта map и заполнение его элементами Чтобы определить объект класса map, мы должны указать, как минимум, типы ключа и значения. Например:mapstring,int word_count;Здесь задается объект word_count типа map, для которого ключом служит объект типа string, а ассоциированным с ним

19.1. Идентификация типов во время выполнения

19.1. Идентификация типов во время выполнения * RTTI позволяет программам, которые манипулируют объектами через указатели или ссылки на базовые классы, получить истинный производный тип адресуемого объекта. Для поддержки RTTI в языке C++ есть два оператора: оператор dynamic_cast

Выяснение типа объекта в период выполнения

Выяснение типа объекта в период выполнения Разработчики ОО-ПО вскоре вырабатывают здоровую неприязнь к любому стилю вычислений, основанному на явном выборе между различными типами объекта. Полиморфизм и динамическое связывание намного предпочтительнее. Однако в

Источник

Глава 19: Динамическая идентификация типов и операторы приведения типа

Динамическая идентификация типов (RTTI)

С динамической идентификацией типов вы, возможно, незнакомы, поскольку это средство отсутствует в таких неполиморфных языках, как С. В неполиморфных языках попросту нет необходимости в получении информации о типе во время выполнения программы, так как тип каждого объекта известен во время компиляции (т.е. еще при написании программы). Но в таких полиморфных языках, как C++, возможны ситуации, в которых тип объекта неизвестен в период компиляции, поскольку точная природа этого объекта не будет определена до тех пор, пока программа на начнет выполняться. Как вы знаете, C++ реализует полиморфизм посредством использования иерархии классов, виртуальных функций и указателей на базовые классы. Указатель на базовый класс можно использовать для ссылки на члены как этого базового класса, так и на члены любого объекта, выведенного из него. Следовательно, не всегда заранее известно, на объект какого типа будет ссылаться указатель на базовый класс в произвольный момент времени. Это выяснится только при выполнении программы — при использовании одного из средств динамической идентификации типов.

Для получения типа объекта во время выполнения программы используйте оператор typeid.

В классе type_info определены следующие public-члены.

bool operator = (const type_info &ob);

bool before(const type_info &ob);

// Пример использования оператора typeid.

using namespace std;

cout typeid применяется к указателю на полиморфный базовый класс (вспомните: полиморфный класс — это класс, который содержит хотя бы одну виртуальную функцию), он автоматически возвращает тип реального объекта, на который тот указывает: будь то объект базового класса или объект класса, выведенного из базового.

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

демонстрируется в следующей программе.

/* Пример применения оператора typeid к иерархии полиморфных классов.

using namespace std;

virtual void f() <>; // делаем класс Base полиморфным

class Derived1: public Base <

class Derived2: public Base <

cout typeid применяется к указателю на базовый класс полиморфного типа, тип реально адресуемого объекта, как подтверждают эти результаты, будет определен во время выполнения программы.

Поскольку оператор typeid обычно применяется к разыменованному указателю (т.е. к

/* Применение оператора typeid к ссылочному параметру.

using namespace std;

virtual void f() <>; // делаем класс Base полиморфным

class Derived1: public Base <

class Derived2: public Base <

/* Демонстрируем применение оператора typeid к ссылочному параметру.

void WhatType(Base &ob)

Например, следующая инструкция совершенно допустима.

cout typeid — получить объект типа type_info (который описывает заданный тип данных), чтобы его можно было использовать в инструкции сравнения типов.

/* Демонстрация использования средства динамической идентификации типов.

Источник

19.1. Идентификация типов во время выполнения

19.1. Идентификация типов во время выполнения

* RTTI позволяет программам, которые манипулируют объектами через указатели или ссылки на базовые классы, получить истинный производный тип адресуемого объекта. Для поддержки RTTI в языке C++ есть два оператора: оператор dynamic_cast поддерживает преобразования типов во время выполнения, обеспечивая безопасную навигацию по иерархии классов. Он позволяет трансформировать указатель на базовый класс в указатель на производный от него, а также преобразовать l-значение, ссылающееся на базовый класс, в ссылку на производный, но только в том случае, если это завершится успешно;

* оператор typeid позволяет получить фактический производный тип объекта, адресованного указателем или ссылкой.

Однако для получения информации о типе производного класса операнд любого из операторов dynamic_cast или typeid должен иметь тип класса, в котором есть хотя бы одна виртуальная функция. Таким образом, операторы RTTI – это события времени выполнения для классов с виртуальными функциями и события времени компиляции для всех остальных типов. В данном разделе мы более подробно познакомимся с их возможностями. Использование RTTI оказывается необходимым при реализации таких приложений, как отладчики или объектные базы данных, когда тип объектов, которыми манипулирует программа, становится известен только во время выполнения путем исследования RTTI-информации, хранящейся вместе с типами объектов. Однако лучше пользоваться статической системой типов C++, поскольку она безопаснее и эффективнее.

19.1.1. Оператор dynamic_cast

Оператор dynamic_cast можно применять для преобразования указателя, ссылающегося на объект типа класса в указатель на тип класса из той же иерархии. Его также используют для трансформации l-значения объекта типа класса в ссылку на тип класса из той же иерархии. Приведение типов с помощью оператора dynamic_cast, в отличие от других имеющихся в C++ способов, осуществляется во время выполнения программы. Если указатель или l-значение не могут быть преобразованы в целевой тип, то dynamic_cast завершается неудачно. В случае приведения типа указателя признаком неудачи служит возврат нулевого значения. Если же l-значение нельзя трансформировать в ссылочный тип, возбуждается исключение. Ниже мы приведем примеры неудачного выполнения этого оператора.

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

virtual int salary();

class manager : public employee <

class programmer : public employee <

void company::payroll( employee *pe ) <

В компании есть разные категории служащих. Параметром функции-члена payroll() класса company является указатель на объект employee, который может адресовать один из типов manager или programmer. Поскольку payroll() обращается к виртуальной функции-члену salary(), то вызывается подходящая замещающая функция, определенная в классе manager или programmer, в зависимости от того, какой объект адресован указателем.

Допустим, класс employee перестал удовлетворять нашим потребностям, и мы хотим его модифицировать, добавив еще одну функцию-член bonus(), используемую совместно с salary() при расчете платежной ведомости. Для этого нужно включить новую функцию-член в классы, составляющие иерархию employee:

virtual int salary(); // ca?ieaoa

virtual int bonus(); // i?aiey

class manager : public employee <

class programmer : public employee <

void company::payroll( employee *pe ) <

// eniieucoaony pe-salary() e pe-bonus()

Если параметр pe функции payroll() указывает на объект типа manager, то вызывается виртуальная функция-член bonus() из базового класса employee, поскольку в классе manager она не замещена. Если же pe указывает на объект типа programmer, то вызывается виртуальная функция-член bonus() из класса programmer.

После добавления новых виртуальных функций в иерархию классов придется перекомпилировать все функции-члены. Добавить bonus() можно, если у нас есть доступ к исходным текстам функций-членов в классах employee, manager и programmer. Однако если иерархия была получена от независимого поставщика, то не исключено, что в нашем распоряжении имеются только заголовочные файлы, описывающие интерфейс библиотечных классов и объектные файлы с их реализацией, а исходные тексты функций-членов недоступны. В таком случае перекомпиляция всей иерархии невозможна.

Если мы хотим расширить функциональность библиотеки классов, не добавляя новые виртуальные функции-члены, можно воспользоваться оператором dynamic_cast.

Этот оператор применяется для получения указателя на производный класс, чтобы иметь возможность работать с теми его элементами, которые по-другому не доступны. Предположим, что мы расширяем библиотеку за счет добавления новой функции-члена bonus() в класс programmer. Ее объявление можно включить в определение programmer, находящееся в заголовочном файле, а саму функцию определить в одном из своих исходных файлов:

virtual int salary();

class manager : public employee <

class programmer : public employee <

Напомним, что payroll() принимает в качестве параметра указатель на базовый класс employee. Мы можем применить оператор dynamic_cast для получения указателя на производный programmer и воспользоваться им для вызова функции-члена bonus():

void company::payroll( employee *pe )

programmer *pm = dynamic_cast programmer* ( pe );

// anee pe oeacuaaao ia iauaeo oeia programmer,

// oi dynamic_cast auiieieony oniaoii e pm aoaao

// oeacuaaou ia ia?aei iauaeoa programmer

// eniieuciaaou pm aey auciaa programmer::bonus()

// anee pe ia oeacuaaao ia iauaeo oeia programmer,

// oi dynamic_cast auiieieony iaoaa?ii

// e pm aoaao niaa??aou 0

// eniieuciaaou ooieoee-?eaiu eeanna employee

приводит свой операнд pe к типу programmer*. Преобразование будет успешным, если pe ссылается на объект типа programmer, и неудачным в противном случае: тогда результатом dynamic_cast будет 0.

Таким образом, оператор dynamic_cast осуществляет сразу две операции. Он проверяет, выполнимо ли запрошенное приведение, и если это так, выполняет его. Проверка производится во время работы программы. dynamic_cast безопаснее, чем другие операции приведения типов в C++, поскольку проверяет возможность корректного преобразования.

Если в предыдущем примере pe действительно указывает на объект типа programmer, то операция dynamic_cast завершится успешно и pm будет инициализирован указателем на объект типа programmer. В противном случае pm получит значение 0. Проверив значение pm, функция company::payroll() может узнать, указывает ли pm на объект programmer. Если это так, то она вызывает функцию-член programmer::bonus() для вычисления премии программисту. Если же dynamic_cast завершается неудачно, то pe указывает на объект типа manager, а значит, необходимо применить более общий алгоритм расчета, не использующий новую функцию-член programmer::bonus().

Оператор dynamic_cast употребляется для безопасного приведения указателя на базовый класс к указателю на производный. Такую операцию часто называют понижающим приведением (downcasting). Она применяется, когда необходимо воспользоваться особенностями производного класса, отсутствующими в базовом. Манипулирование объектами производного класса с помощью указателей на базовый обычно происходит автоматически, с помощью виртуальных функций. Однако иногда использовать виртуальные функции невозможно. В таких ситуациях dynamic_cast предлагает альтернативное решение, хотя этот механизм в большей степени подвержен ошибкам, чем виртуализация, и должен применяться с осторожностью.

Одна из возможных ошибок – это работа с результатом dynamic_cast без предварительной проверки на 0: нулевой указатель нельзя использовать для адресации объекта класса. Например:

void company::payroll( employee *pe )

programmer *pm = dynamic_cast( pe );

// iioaioeaeuiay ioeaea: pm eniieucoaony aac i?iaa?ee cia?aiey

static int variablePay = 0;

Результат, возвращенный dynamic_cast, всегда следует проверять, прежде чем использовать в качестве указателя. Более правильное определение функции company::payroll() могло бы выглядеть так:

void company::payroll( employee *pe )

if ( programmer *pm = dynamic_cast( pe ) ) <

// eniieuciaaou pm aey auciaa programmer::bonus()

// eniieuciaaou ooieoee-?eaiu eeanna employee

Результат операции dynamic_cast используется для инициализации переменной pm внутри условного выражения в инструкции if. Это возможно, так как объявления в условиях возвращают значения. Ветвь, соответствующая истинности условия, выполняется, если pm не равно нулю: мы знаем, что операция dynamic_cast завершилась успешно и pe указывает на объект programmer. В противном случае результатом объявления будет 0 и выполняется ветвь else. Поскольку теперь оператор и проверка его результата находятся в одной инструкции программы, то невозможно случайно вставить какой-либо код между выполнением dynamic_cast и проверкой, так что pm будет использоваться только тогда, когда содержит правильный указатель.

В предыдущем примере операция dynamic_cast преобразует указатель на базовый класс в указатель на производный. Ее также можно применять для трансформации l-значения типа базового класса в ссылку на тип производного. Синтаксис такого использования dynamic_cast следующий:

dynamic_cast Type & &( lval )

где Type& – это целевой тип преобразования, а lval – l-значение типа базового класса. Операнд lval успешно приводится к типу Type& только в том случае, когда lval действительно относится к объекту класса, для которого один из производных имеет тип Type.

Поскольку нулевых ссылок не бывает (см. раздел 3.6), то проверить успешность выполнения операции путем сравнения результата (т.е. возвращенной оператором dynamic_cast ссылки) с нулем невозможно. Если вместо указателей используются ссылки, условие

if ( programmer *pm = dynamic_cast programmer* ( pe ) )

нельзя переписать в виде

if ( programmer &pm = dynamic_cast& programmer& &( pe ) )

Для извещения об ошибке в случае приведения к ссылочному типу оператор dynamic_cast возбуждает исключение. Следовательно, предыдущий пример можно записать так:

void company::payroll( employee &re )

// eniieuciaaou rm aey auciaa programmer::bonus()

// eniieuciaaou ooieoee-?eaiu eeanna employee

Когда следует употреблять ссылочный вариант dynamic_cast вместо указательного? Это зависит только от желания программиста. При его использовании игнорировать ошибку приведения типа и работать с результатом без проверки (как в указательном варианте) невозможно; с другой стороны, применение исключений увеличивает накладные расходы во время выполнения программы (см. главу 11).

Читайте также

Глава 27 Динамическая загрузка во время выполнения

Глава 27 Динамическая загрузка во время выполнения Загрузка разделяемых (совместно используемых) объектов во время выполнения может оказаться полезным способом для структурирования собственных приложений. Если правильно организовать этот процесс, то тогда можно будет

Идентификация посетителей

Идентификация посетителей Один и тот же пользователь может просматривать достаточно большое число страниц, запрашивать на сервере множество разных файлов, поэтому первая задача статистики – определение принадлежности различных запросов одному пользователю, или,

Единственность и идентификация

Единственность и идентификация Предыдущий раздел был посвящен запросам QueryInterface, которые представляют собой ответы типа «да/нет» вызывающим объектам. QueryInterface действительно возвращает S_OK (да) или E_NOINTERFACE (нет). Впрочем, когда QueryInterface возвращает S_OK, то он также возвращает

15.8.2. Emacs и отладка во время выполнения

15.8.2. Emacs и отладка во время выполнения Для обнаружения ошибок времени выполнения Emacs предоставляет аналогичную возможность интеграции с символическим отладчиком, т.е. разработчик может использовать какой-либо Emacs-режим для установки контрольных точек в программах и

15.8.2. Emacs и отладка во время выполнения

15.8.2. Emacs и отладка во время выполнения Для обнаружения ошибок времени выполнения Emacs предоставляет аналогичную возможность интеграции с символическим отладчиком, т.е. разработчик может использовать какой-либо Emacs-режим для установки контрольных точек в программах и

1.4.1. Кодирование во время выполнения

1.4.1. Кодирование во время выполнения Мы уже упоминали директивы load и require. Важно понимать, что это не встроенные предложения и не управляющие конструкции; на самом деле это методы. Поэтому их можно вызывать, передавая переменные или выражения как параметры, в том числе

8.6. Определение типа объекта во время выполнения

8.6. Определение типа объекта во время выполнения ПроблемаВо время выполнения требуется динамически узнавать тип определенного класса.РешениеДля запроса, на объект какого типа указывает адрес объекта, используйте идентификацию типов во время выполнения (обычно

2.4.2. Время установки Windows 7 и время жизни аккумулятора

2.4.2. Время установки Windows 7 и время жизни аккумулятора Если вы устанавливаете Windows 7 на ноутбук или нетбук, желательно подключить его к сети питания. Если это невозможно, тогда лучше не начинать установку Windows. Хотя весь процесс установки занимает около 20–25 минут (во всяком

Идентификация и аутентификация

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

3 Абсолютная идентификация

3 Абсолютная идентификация Ошибки в базах данных, кража личности, нелегальная иммиграция и нераскрытые преступления стали распространенными явлениями в нашей жизни, поэтому многие политики обращают свои надежды к достижениям в области технологий биометрической

Идентификация по ДНК

Идентификация по ДНК Дезоксирибонуклеиновая кислота, более известная под названием ДНК, – молекула, которая одновременно разделяет и объединяет нас. При помощи ДНК наследственные признаки передаются следующим поколениям, сходство ДНК характерно для семей и кланов,

Источник

Понравилась статья? Поделиться с друзьями:

Не пропустите наши новые статьи:

  • какой оператор код 995 какой оператор и регион город
  • какой оператор использует код 961
  • какой оператор имеет код 958
  • какой оператор в языке программирования паскаль выполняет целочисленное деление 2 натуральных чисел
  • какой оператор 943 и регион код

  • Операционные системы и программное обеспечение
    0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest
    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии