Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ООП на языке С++.docx
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2 Мб
Скачать
☆

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

Динамическая идентификация типа (RTTI–Run-Time Type Identification) характерна для языков, в которых поддерживается полиморфизм. В этих языках возможны ситуации, в которых тип объекта на этапе компиляции неизвестен.

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

Информацию о типе объекта получают с помощью оператора typeid, при использовании которого следует подключить заголовочный файл <typeinfo.h>

Оператор typeid имеет две формы:

  1. typeid (объект)

  2. typeid (имя_типа)

Оператор typeid возвращает ссылку на объект типа type_info.

В классе type_info определены следующие открытые члены:

bool operator==(const type_info&ob)const;

bool operator!=(const type_info&ob)const;

const char* name()const;

Перегруженные операции == и != обеспечивают сравнение типов.

Функция name() возвращает указатель на имя типа.

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

Пример 7.2.1.

#include<iostream.h>

#include<typeinfo.h>

class Base{

virtual void f(){};

//…

};

class Derived: public Base{

//…

};

void main()

{int i;

Base ob,*p;

Derived ob1;

cout<<typeid(i).name(); //Выводится int

p=&ob1;

cout<<typeid(*p).name(); //Выводится Derived

}

Пример 7.2.2.

#include<iostream.h>

#include<typeinfo.h>

class Base{

virtual void f(){};

//…

};

class Derived: public Base{

//…

};

void WhatType(Base& ob)

{cout<< typeid(ob).name()<<endl;

}

void main()

{

Base ob;

Derived ob1;

WhatType(ob); // Выводится Base

WhatType(ob1); // Выводится Derived

}

Пример 7.2.3.

class X{

virtual void f(){};

};

class Y{

virtual void f(){};

};

void main()

{X x1,x2;

Y y1;

if(typeid(x1)==typeid(x2))cout<<“тип одинаков”;

else cout<<“тип не одинаков”;

if(typeid(x1)!=typeid(y1)) cout<<“тип неодинаков”;

…

if(typeid(x1)==typeid(X)) cout<<“x1 имеет тип X”;

…

}

При использовании указателей на объект, например typeid(*p), если p==NULL, то возникает исключительная ситуация bad_typeid.

7.3. Безопасное приведение типа

Приведение типа вида (имя_типа) выражение, определенное в стандарте языка С, может привести к ошибкам. Ошибка может произойти, когда вы попытаетесь привести один объект к другому при их несовместимости.

Пример 7.3.1.

struct A

{int i};

struct B

{char* s;}

void f(A* x)

{B* p=(B*)x;

cout<<p–>s;}

void main()

{B b;

A a,*r;

b.s=new char[5];

b.s=“abcd”;

a.i=15;

r=&a;

f(r);//Здесь ошибка

r=(A*)(&b);

f(r);//А так ошибки нет

}

Для решения проблемы безопасного приведения типов в С++ введены операторы:

dynamic_cast, static_cast, const_cast, reinterpret_cast.

Оператор dynamic_cast

Оператор dynamic_cast предназначен для безопасного приведения типа одного указателя или ссылки в другой. Основное назначение оператора dynamic_cast заключается в реализации приведения полиморфных типов.

Синтаксис оператора dynamic_cast:

dynamic_cast<целевой_тип>(выражение)

Здесь ‘целевой_тип’ – это тип, которым должен стать тип параметра ‘выражение’ после выполнения приведения типа. Оператор выполняется успешно, когда указатель (или ссылка) после приведения типа становится указателем на объект целевого типа либо на объект производного от целевого типа. При невозможности приведения результатом является либо NULL, если приводятся указатели, либо возбуждается исключительная ситуация bad_cast, если приводятся ссылки.

Пример 7.3.2.

Base* bp,b;

Derived* dp,d;

bp=&d;

dp= dynamic_cast<Derived*>(bp);

if(dp)cout<<“приведение прошло успешно”;

bp=&b;

dp=dynamic_cast<Derived*>(bp);

if(!dp)cout<<“приведение невозможно”;

Оператор dynamic_cast в некоторых случаях можно использовать вместо typeid.

Base* bp;

Derived* dp;

Приведение типов можно выполнить так

if (typeid(*bp)==typeid(Derived))dp=(Derived*)bp;

А можно и короче

dp=dynamic_cast<Derived*>(bp);

Оператор const_cast

const_cast<целевой_тип>(выражение)

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

void f(const int* p)

{int* v;

v=const_cast<int*>(p);

*v=2*(*v);

}

Оператор static_cast

static_cast<целевой_тип> (выражение)

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

int i;

float f;

f=199.22;

i=static_cast<int>(f);

Оператор reinterpret_cast

reinterpret_cast<целевой_тип>(выражение)

Дает возможность преобразовать указатель одного типа в указатель совершенно другого типа. Он также позволяет приводить указатель к типу целого или целое к типу указателя. Это преобразование также опасно, как и старый С-стиль преобразования.

int i;

char* p=“Это строка”;

i=reinterpret_cast<int>(p);

cout<<i;