Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Тема 14. Динамическая идентификация и приведение типов

Поиск

 

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

Информацию о типе объекта получают с помощью оператора

typeid (объект),

который возвращает ссылку на объект типа type_info, который и описывает тип объекта объект. В классе type_infoопределены следующие открытые члены:

 

bool operator ==(const type_info & объект); // сравнение типов

bool operator!=(const type_info & объект); // сравнение типов

bool before (const type_info & объект); // сравнение типов

const char *name(); // указатель на имя объекта

 

Хотя оператор typeid позволяет получать типы разных объектов, наиболее полезен он будет, если в качестве его аргумента задать указатель полиморфного базового класса. В этом случае оператор автоматически возвращает тип реального объекта, на который ссылается указатель. Таким образом, с помощью оператора typeid во время выполнения программы можно определить тип объекта, на который ссылается указатель базового класса. То же самое относится и к ссылкам. Если в качестве аргумента оператора typeid указана ссылка на объект полиморфного класса, оператор возвращает тип реального объекта, на который имеется ссылка. Когда оператор typeid применяют к неполиморфному классу, получают указатель или ссылку базового типа.

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

 

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

# include < iostream. h>

# include < typeinfo. h>

class Base

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

};

class Der1: public Base {…};

class Der2: public Base {…};

int main (void)

{ int i;

Base *p, baseof;

Der1 d1; Der2 d2;

cout <<”\n Тип переменной i – это”<< typeid(i).name() << endl;

// обработка полиморфных типов

p=&baseof;

cout <<”Указатель p ссылается на объект типа”;

cout << typeid (*p). name ()<< endl;

p=&d1;

cout <<”Указатель p ссылается на объект типа”<< typeid (*p). name ();

p=&d2;

cout <<”Указатель p ссылается на объект типа”<< typeid (*p). name ();

return 0;

}

 

Программа выводит на экран следующую информацию:

Тип переменной i – это int

Указатель p ссылается на объект типа Base

Указатель p ссылается на объект типа Der1

Указатель p ссылается на объект типа Der2

 

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

void func(Base& ref)

{

cout <<”ref - ссылка на объект типа”<< typeid (ref). name();

}

 

Для объектов d1, d2 будет происходить правильная их идентификация при вызовах: func(d1) и func(d2) соответственно.

Главное достоинство оператора typeid заключается в возможности идентификации неизвестных на этапе компиляции типов объектов.

Рассмотрим пример программы, в которой определена простая иерархия классов, предназначенных для рисования на экране разного рода геометрических фигур. На вершине иерархии находится абстрактный класс Shape, который наследуют четыре класса: Line, Square, Rectagle, NullShape.

Функция generator() генерирует объект и возвращает указатель на него. То, какой именно объект создается, определяет генератор случайных чисел rand (). В функции main () реализован вывод получающихся объектов разных типов на экран, исключая объекты типа NullShape.

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

 

# include < iostream.h >

# include < cstdlib.h >

include < typeinfo.h >

class Shape

{ public:

virtual void example()=0;

};

class Rectangle: public Shape

{ public:

void example() { cout <<”Прямоугольник\n”;}

};

 

 

class Triangle: public Shape

{ public:

void example() { cout <<”\nТреугольник\n”;}

};

class Line: public Shape

{ public:

void example() { cout <<”\nЛиния\n”;}

};

class NullShape: public Shape

{ public:

void example() {}

};

 

// фабрика производных от класса Shape объектов

 

Shape *generator()

{ switch (rand ()%4)

{ case 0: return new Line;

case 1: return new Rectangle;

case 2: return new Triangle;

case 3: return new NullShape;

}

return NULL;

}

 

 

int main (void)

{ int i;

Shape *p;

for (i=0; i<10; i++)

{ p=generator (); // создание следующего объекта

cout << typeid (*p). name ()<< endl;

// рисует объект, если он не типа NullShape

if (typeid (*p)!= typeid (NullShape)) p->example();

}

return 0;

}

 

Оператор typeid может работать с классами-шаблонами.

При выполнении программы, написанной на языке С++, могут выполняться преобразования типов: явные и неявные. Явные преобразования типов всегда выполняются по инициативе программиста, и для этого в языке С++ существуют: операция приведения типа, унаследованная из языка Си, и ее функциональная форма записи, введенная в язык С++; операции const_cast, dynamic_cast, reinterpret_cast и static_cast. Последние операции являются более надежными операциями преобразования типов и их следует использовать во всех необходимых случаях.

Операция const-cast

Данная операция применяется для того, чтобы аннулировать действие модификатора const:

const int i;

int *p=const_cast <int* >(&i); // получим обычный указатель

 

В общем случае эта операция имеет следующий формат:

const_cаst <T>(V), где тип T должен быть таким же, как и тип V (обычно это указатель). Операция возвращает результат типа Т. Необходимость этой операции обусловлена тем, что при проектировании функции не обязательно описывать не измеряемые в ней параметры как const, хотя это и рекомендуется. Правила языка С++ запрещают передачу константного указателя на место обычного. Поэтому операция const_cast введена для того, чтобы обойти это ограничение. Естественно, что в подобном случае функция не должна изменять значение, на которое ссылается передаваемый указатель.

Преобразование типов во время компиляции (операция static_cast)

Операция static_cast выполняется компилятором и должна применяться только в том случае, когда без нее нельзя обойтись. В качестве примеров целесообразного применения операции static_cast можно назвать преобразование указателя void * к указателю на необходимый тип, приведение целого типа к типу перечисления и для других преобразований родственных типов.

Преобразование типов во время выполнения программы (dynamic_cast)

Операцию dynamic_cast обычно применяют для полиморфных объектов и для понижающего преобразования виртуальных базовых классов. При этом операция использует механизм идентификации типа во время выполнения программы (Run-Time Type Information, RTTI).

Преобразование «на свой риск и страх» (reinterpret_cast) применяется достаточно редко, когда нужно осуществить «экзотические» преобразования не связанных между собой типов.

 

Основная литература – 6 [Гл. 7, 178-199], 8 [Гл. 12, 357-381].

 

Вопросы контроля

1. Опишите операции, которые можно выполнить с помощью оператора typeid.

2. Тип какого объекта можно определить с помощью оператора typeid?

3. Для чего нужна операция преобразования типа const_cast?

4. Для чего нужна операция преобразования типа dynamic_cast?

5. Для чего нужны операции static_cast и reinterpret_cast?

Тема 15. Стандартная библиотека языка С++.



Поделиться:


Последнее изменение этой страницы: 2016-12-13; просмотров: 260; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.116.14.12 (0.006 с.)