Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Эта программа генерирует такие результаты.



Объект o1 имеет тип class myclass< int>

Объект o2 имеет тип class myclass< int>

Объект o3 имеет тип class myclass< double>

Объекты o1 и o2 имеют одинаковый тип.

Объекты o1 и o3 имеют разные типы.

Как видите, несмотря на то, что два объекта являются экземплярами одного и того же шаблонного класса, если их параметризованные данные не совпадают, они не эквивалентны по типу. В этой программе объект o1 имеет тип myclass< int> , а объект o3 — тип myclass< double> . Таким образом, это объекты разного типа.

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

// Шаблонная версия figure-иерархии.

#include < iostream>

#include < cstdlib>

using namespace std;

template < class T>

Class figure

{

  protected:

    T x, y;

  public:

    figure(T i, T j) {

      x = i;

      у = j;

    }

    virtual T area() = 0;

};

template < class T>

class triangle: public figure< T>

{

  public:

    triangle(T i, T j): figure< T> (i, j) {}

    T area() {

      return x * 0.5 * y;

    }

};

template < class T>

class rectangle: public figure< T>

{

  public:

    rectangle(T i, T j): figure< T> (i, j) {}

    T area() {

      return x * y;

    }

};

template < class T>

class circle: public figure< T>

{

  public:

    circle(T i, T j=0): figure< T> (i, j) {}

    T area() {

      return 3.14 * x * x;

    }

};

// Фабрика объектов, генерируемых из класса figure.

figure< double> *generator()

{

  switch(rand() % 3 ) {

    case 0: return new circle< double> (10.0);

    case 1: return new triangle< double> (10.1, 5.3);

    case 2: return new rectangle< double> (4.3, 5.7);

  }

  return 0;

}

Int main()

{

  figure< double> *p;

  int i;

  int t=0, c=0, r=0;

  // генерируем и подсчитываем объекты

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

    p = generator();

    cout < < " Объект имеет тип " < < typeid(*p).name();

    cout < < ". ";

    // учитываем объект

    if(typeid(*p) == typeid(triangle< double> )) t++;

    if(typeid(*p) == typeid(rectangle< double> )) r++;

    if(typeid(*p) == typeid(circle< double> )) c++;

    cout < < " Площадь равна " < < p-> area() < < endl;

  }

  cout < < endl;

  cout < < " Сгенерированы такие объекты: ";

  cout < < " треугольников: " < < t < < endl;

  cout < < " прямоугольников: " < < r < < endl;

  cout < < " кругов: " < < с < < endl;

  return 0;

}

Вот как выглядит возможный результат выполнения этой программы.

Объект имеет тип class rectangle< double>. Площадь равна 24.51

Объект имеет тип class rectangle< double>. Площадь равна 24.51

Объект имеет тип class triangle< double>. Площадь равна 26.765

Объект имеет тип class triangle< double>. Площадь равна 26.765

Объект имеет тип class rectangle< double>. Площадь равна 24.51

Объект имеет тип class triangle< double>. Площадь равна 26.765

Объект имеет тип class circle< double>. Площадь равна 314

Объект имеет тип class circle< double>. Площадь равна 314

Объект имеет тип class triangle< double>. Площадь равна 26.765

Объект имеет тип class rectangle< double>. Площадь равна 24.51

Сгенерированы такие объекты:

  треугольников: 4

  прямоугольников: 4

  кругов: 2

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

Операторы приведения типов

В C++ определено пять операторов приведения типов. Первый оператор (он описан выше в этой книге), применяемый в обычном (традиционном) стиле, был с самого начала встроен в C++. Остальные четыре (dynamic_cast, const_cast, reinterpret_cast и static_cast) были добавлены в язык всего несколько лет назад. Эти операторы предоставляют дополнительные " рычаги управления" характером выполнения операций приведения типа. Рассмотрим каждый из них в отдельности.

Оператор dynamic_cast

Оператор dynamic_cast выполняет операцию приведения полиморфных типов во время выполнения программы.

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

dynamic_cast< type> (expr)

Здесь элемент type означает новый тип, который является целью выполнения этой операции, а элемент expr— выражение, приводимое к этому новому типу. Тип type должен быть представлен указателем или ссылкой, а выражение expr должно приводиться к указателю или ссылке. Таким образом, оператор dynamic_cast можно использовать для преобразования указателя одного типа в указатель другого или ссылки одного типа в ссылку другого.

Этот оператор в основном используется для динамического выполнения операций приведения типа среди полиморфных типов. Например, если даны полиморфные классы В и D, причем класс D выведен из класса В, то с помощью оператора dynamic_cast всегда можно преобразовать указатель D* в указатель В*, поскольку указатель на базовый класс всегда можно использовать для указания на объект класса, выведенного из базового. Однако оператор dynamic_cast может преобразовать указатель В* в указатель D* только в том случае, если адресуемым объектом действительно является объект класса D. И, вообще, оператор dynamic_cast будет успешно выполнен только при условии, если разрешено полиморфное приведение типов, т.е. если указатель (или ссылка), приводимый к новому типу, может указывать (или ссылаться) на объект этого нового типа или объект, выведенный из него. В противном случае, т.е. если заданную операцию приведения типов выполнить нельзя, результат действия оператора dynamic_cast оценивается как нулевой, если в этой операции участвуют указатели. (Если же попытка выполнить эту операцию оказалась неудачной при участии в ней ссылок, генерируется исключение типа bad_cast.)

Рассмотрим простой пример. Предположим, что класс Base — полиморфный, а класс Derived выведен из класса Base.

Base *bp, b_ob;

Derived *dp, d_ob;

bp = & d_ob; // Указатель на базовый класс указывает на объект класса Derived.

dp = dynamic_cast< Derived *> (bp); // Приведение к указателю на производный класс разрешено.

if(dp) cout < < " Приведение типа прошло успешно! ";

Здесь приведение указателя bp (на базовый класс) к указателю dp (на производный класс) успешно выполняется, поскольку bp действительно указывает на объект класса Derived. Поэтому при выполнении этого фрагмента кода будет выведено сообщение Приведение типа прошло успешно! . Но в следующем фрагменте кода попытка совершить операцию приведения типа будет неудачной, поскольку bp в действительности указывает на объект класса Base, и неправомерно приводить указатель на базовый класс к типу указателя на производный, если адресуемый им объект не является на самом деле объектом производного класса.

bp = & b_ob; /* Указатель на базовый класс ссылается на объект класса Base. */

dp = dynamic_cast< Derived *> (bp); // ошибка!

if(! dp) cout < < " Приведение типа выполнить не удалось";

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

В следующей программе демонстрируются различные ситуации применения оператора dynamic_cast.

// Использование оператора dynamic_cast.

#include < iostream>

using namespace std;

class Base {

  public:

    virtual void f() { cout < < " В классе Base."; }

    //...

};

class Derived: public Base {

  public:

    void f() { cout < < " В классе Derived."; }

};

Int main()

{

  Base *bp, b_ob;

  Derived *dp, d_ob;

  dp = dynamic_cast< Derived *> (& d_ob);

  if(dp) {

    cout < < " Приведение типов " < < " (из Derived * в Derived *) реализовано.";

    dp-> f();

  }

  else cout < < " Ошибка";

  cout < < endl;

  bp = dynamic_cast< Base *> (& d_ob);

  if(bp) {

    cout < < " Приведение типов " < < " (из Derived * в Base *) реализовано.";

    bp-> f();

  }

  else cout < < " Ошибка";

  cout < < endl;

  bp = dynamic_cast< Base *> (& b_ob);

  if(bp) {

    cout < < " Приведение типов " < < " (из Base * в Base *) реализовано.";

    bp-> f();

  }

  else cout < < " Ошибка";

  cout < < endl;

  dp = dynamic_cast< Derived *> (& b_ob);

  if(dp) cout < < " Ошибка";

  else

    cout < < " Приведение типов " < < " (из Base * в Derived *) не реализовано.";

  cout < < endl;

  bp = & d_ob; // bp указывает на объект класса Derived

  dp = dynamic_cast< Derived *> (bp);

  if(dp) {

    cout < < " Приведение bp к типу Derived *" < < " реализовано, поскольку bp действительно" < < " указывает на объект класса Derived.";

    dp-> f();

  }

  else cout < < " Ошибка";

  cout < < endl;

  bp = & b_ob; // bр указывает на объект класса Base

  dp = dynamic_cast< Derived *> (bp);

  if(dp) cout < < " Ошибка";

  else {

    cout < < " Теперь приведение bp к типу Derived *" < < " не реализовано, поскольку bp" < < " в действительности указывает на объект" < < " класса Base.";

  }

  cout < < endl;

  dp = & d_ob; // dp указывает на объект класса Derived

  bp = dynamic_cast< Base *> (dp);

  if(bp) {

    cout < < " Приведение dp к типу Base * реализовано.";

    bp-> f();

  }

  else cout < < " Ошибка";

  return 0;

}


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-17; Просмотров: 1099; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.048 с.)
Главная | Случайная страница | Обратная связь