Лекции.ИНФО


При выполнении этой программы получены такие результаты.



Тип переменной i: int

Тип переменной f: float

Тип переменной ob: class myclass

Типы переменных i и j одинаковы.

Типы переменных i и f неодинаковы.

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

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

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

*/

#include <iostream>

#include <typeinfo>

using namespace std;

class Base {

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

 // . . .

};

class Derived1: public Base {

 // . . .

};

class Derived2: public Base {

 // ...

};

Int main()

{

 Base *p, baseob;

 Derived1 ob1;

 Derived2 ob2;

 p = &baseob;

 cout << "Переменная p указывает на объект типа ";

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

 p = &ob1;

 cout << "Переменная p указывает на объект типа ";

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

 p = &ob2;

 cout << "Переменная p указывает на объект типа ";

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

 return 0;

}

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

Переменная р указывает на объект типа Base

Переменная р указывает на объект типа Derived1

Переменная р указывает на объект типа Derived2

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

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

Поскольку оператор typeid обычно применяется к разыменованному указателю (т.е. к указателю, к которому уже применен оператор "*"), для обработки ситуации, когда этот разыменованный указатель оказывается нулевым, создано специальное исключение. В этом случае оператор typeid генерирует исключение типа bad_typeid.

Ссылки на объекты иерархии полиморфных классов работают подобно указателям. Если оператор typeid применяется к ссылке на полиморфный класс, он возвращает тип объекта, на который она реально ссылается, и это может быть объект не базового, а производного типа. Описанное средство чаще всего используется при передаче объектов функциям по ссылке. Например, в следующей программе функция WhatType() объявляет ссылочный параметр на объекты типа Base. Это значит, что функции WhatType() можно передавать ссылки на объекты типа Base или ссылки на объекты любых классов, производных от Base. Оператор typeid, примененный к такому параметру, возвратит реальный тип объекта, переданного функции.

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

*/

#include <iostream>

#include <typeinfo>

using namespace std;

class Base {

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

 // . . .

};

class Derived1: public Base {

 // . . .

};

class Derived2: public Base {

 // . . .

};

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

*/

void WhatType(Base &ob)

{

 cout << "Параметр ob ссылается на объект типа ";

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

}

Int main()

{

 int i;

 Base baseob;

 Derived1 obi;

 Derived2 ob2;

 WhatType(baseob);

 WhatType(ob1);

 WhatType(ob2);

 return 0;

}

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

Параметр ob ссылается на объект типа Base

Параметр ob ссылается на объект типа Derived1

Параметр ob ссылается на объект типа Derived2

Существует еще одна версия применения оператора typeid, которая в качестве аргумента принимает имя типа. Формат ее таков.

tуре id(имя_типа)

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

cout << typeid(int).name();

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

Пример RTTI-приложения

В следующей программе показано, насколько полезной может быть средство динамической идентификации типов (RTTI). Здесь используется модифицированная версия иерархии классов геометрических фигур из главы 15, которая вычисляет площадь круга, треугольника и прямоугольника. В данной программе определена функция fасtorу(), предназначенная для создания экземпляра круга, треугольника или прямоугольника. Эта функция возвращает указатель на созданный объект. (Функция, которая генерирует объекты, иногда называется фабрикой объектов.) Конкретный тип создаваемого объекта определяется в результате обращения к функции rand() С++-генератора случайных чисел. Таким образом, мы не можем знать заранее, объект какого типа будет сгенерирован. Программа создает десять объектов и подсчитывает количество созданных фигур каждого типа. Поскольку при вызове функции fасtorу() может быть сгенерирована фигура любого типа, для определения типа реально созданного объекта в программе используется оператор typeid.

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

*/

#include <iostream>

#include <cstdlib>

using namespace std;

class figure {

 protected:

  double x, y;

 public:

  figure(double i, double j) {

   x = i;

   У = j;

  }

  virtual double area() = 0;

};

class triangle : public figure {

 public:

  triangle(double i, double j) : figure(i, j) {}

  double area() {

   return x * 0.5 * y;

  }

};

class rectangle : public figure {

 public:

  rectangle(double i, double j) : figure (i, j) {}

  double area() { return x * y;}

};

class circle : public figure {

 public:

  circle(double i, double j=0) : figure(i, j) {}

  double area() {return 3.14 * x * x;}

};

// Фабрика объектов класса figure.

figure *factory()

{

 switch(rand() % 3 ) {

  case 0: return new circle (10.0);

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

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

 }

 return 0;

}

Int main()

{

 figure *p; // указатель на базовый класс

 int i;

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

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

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

  p = factory(); // генерируем объект

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

  cout << ". ";

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

  if(typeid(*р) == typeid(triangle)) t++;

  if(typeid(*p) == typeid(rectangle)) r++;

  if(typeid(*p) == typeid(circle)) c++;

  // отображаем площадь фигуры

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

 }

 cout << endl;

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

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

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

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

 return 0;

}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

 кругов: 2

Применение оператора typeid к шаблонным классам

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

/* Использование оператора typeid с шаблонными классами.

*/

#include <iostream>

using namespace std;

template <class T>

class myclass {

  T a;

 public:

  myclass(T i) { a = i; }

  // . . .

};

Int main()

{

 myclass<int> o1(10), o2(9);

 myclass<double> o3(7.2);

 cout << "Объект o1 имеет тип ";

 cout << typeid(o1).name() << endl;

 cout << "Объект o2 имеет тип ";

 cout << typeid(o2).name() << endl;

 cout << "Объект o3 имеет тип ";

 cout << typeid(o3).name() << endl;

 cout << endl;

 if(typeid(o1) == typeid(o2))

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

 if(typeid(o1) == typeid(o3)) cout << "Ошибка";

 else cout << "Объекты o1 и o3 имеют разные типы.";

 return 0;

}









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

  1. A. Притяжения и отталкивания, силы отталкивания больше на малых расстояниях, чем силы притяжения. Б. Притяжения и отталкивания, силы отталкивания меньше на малых расстояниях, чем силы притяжения.
  2. Adjective and adverb. Имя прилагательное и наречие. Степени сравнения.
  3. D. Правоспособность иностранцев. - Ограничения в отношении землевладения. - Двоякий смысл своего и чужого в немецкой терминологии. - Приобретение прав гражданства русскими подданными в Финляндии
  4. D. ПРЕИМУЩЕСТВА ПРИСОЕДИНЕНИЯ К ГААГСКОМУ СОГЛАШЕНИЮ
  5. F70.99 Умственная отсталость легкой степени без указаний на нарушение поведения, обусловленная неуточненными причинами
  6. F71.98 Умственная отсталость умеренная без указаний на нарушение поведения, обусловленная другими уточненными причинами
  7. I Использование заемных средств в работе предприятия
  8. I. Методические принципы физического воспитания (сознательность, активность, наглядность, доступность, систематичность)
  9. I. О НОВОПРИБЫВШИХ ГРАЖДАНАХ.
  10. I. Предприятия крупного рогатого скота
  11. I. Придаточные, которые присоединяются непосредственно к главному предложению, могут быть однородными и неоднородными.
  12. I. СИЛЬНЫЕ СТОРОНЫ ПРЕДПРИЯТИЯ


Последнее изменение этой страницы: 2016-03-17; Просмотров: 89;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная