Динамическая информация о типе 


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



ЗНАЕТЕ ЛИ ВЫ?

Динамическая информация о типе



Еще одна новинка ANSI C++ — динамическая информация о типе — предназначена именно для того, что вы ожидали: для предоставления информации о типе объекта во время выполнения программы. Вы можете использовать ее для сравнения типов объектов и для доступа к строкам, в которых они описываются.

ANSI С и ранние версии C++ не имеют средств, эквивалентных динамической информации о типе. Раньше для определения размера объекта в байтах вы могли использовать sizeof (конечно, у вас и сейчас остается та­кая возможность), однако не существовало никаких стандартных способов определить, принадлежат ли объек­ты одному типу данных или нет.

Оператор typeid возвращает объект класса Type_info, который описывает тип объекта. Вы можете исполь­зовать typeid как для простых объектов встроенных типов, подобных hit и double, так и для классов, струк­тур, массивов и других ваших собственных типов. Вы можете также использовать оператор typeid для сравне­ния типов данных на эквивалентность (равно — не равно) или по алфавиту.

Для использования typeid следует включить в программу заголовочный файл TYPEINFO.H. Оператор воз­вращает объекты класса Type_info, в этом классе имеются функции-члены, к которым вы можете обратиться. Одна из этих функций, nameO, предназначается для доступа к имени объекта. Можно использовать ее сле­дующим образом:

int count;

cout << typeid(count).name() «endl;

Оператор вывода отобразит int — имя типа данных переменной count. Вы можете также сравнить типы данных объектов следующим образом:

int i; int j; if (typeid(i) == typeid(j))

cout «"i and j are the same types" «endl;

Или же можно использовать оператор!= для проверки на неравенство типов данных:

if (typeid(i)!= typeid(j))

cout << "i and j are not the same types" << endl;

Вы можете также вызвать функцию beforeO для сравнения типов в алфавитном порядке (синтаксис неук­люжий и сомнительного свойства, поэтому легче провести лексическое сравнение строк, возвращаемых функ­цией nameO):

if (typeid(i).before(typeid(d)))

cout << "i's type name is lexically before d's type name";

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

ЗАМЕЧАНИЕ

Вопреки вышесказанному и справочным руководствам Borland, проверка показывает; что оператор typeid не возбуждает исключительную ситуацию для разыменованного нулевого указателя. Скорее всего, причина этому -ошибка в компиляторе.

В листинге 15.20 демонстрируется использование оператора typeid. Вы можете скомпилировать и запус­тить эту программу как DOS- или Easy Win-приложение. (Не обращайте внимания на предупреждения компи­лятора о том, что объявленные переменные не используются.)

Листинг 15.20. TYPEINFO.CPP (демонстрация оператора typeid)

 

«include <iostream.h> «include <string.h> «include <typeinfo.h>

class AnyClass { public:

AnyClass(int c) { count = c; } private:

int count;

«pragma warn -use

int main() {

char c;

int i;

double d;

AnyClass a(1);

AnyClass *pa = new AnyClasst2);

«typeid(c).name() «endl;

«typeid(i).name() << endl;

«typeid(d).name() «endl;

<< typeid(a).name() << endl;

<< typeid(pa).name() «endl;

«typeid(*pa).name() << endl;

«typeid(typeid(i)).name() «endl;

cout << endl; // Начать с новой строки

// Следующие строки не выводят корректные имена' типов, // это следствие ошибки в ВС++ 4.

if (typeid(c)!= typeid(d)) cout «typeid(c).name() «" and "<< typeid(d).name() << " are not equivalent." << endl; /

// Очевидно, необходимо использовать name() только один раз в // операторе вывода в поток. Следующие строки работают правильно.

 
 

 

if (typeid(c)!= typeid(d)) { cout << typeid(c).name() << " and "; cout << typeid(d).name() «" are not equivalent." << endl;

// Сравнить обычный и динамический объекты одного и того же типа if (typeid(a) == typeid(*pa)) cout << "a and *pa are objects of the same types" «endl;

// Демонстрация обработки исключительной ситуации Bad_typeid try {

cout << endl;

cout << "Using a dereferenced null pointer typeid" << endl;

int *p; // Define a pointer

 

p = 0; // Assign null to the pointer

cout «"Name: " «typeid(«p). name() «endl;

cout «"Borland C++ bug. This should not appear.'

p = new int; // Never executes

delete p; // Never executes > catch (Bad_typeid x) {

cout << "Error: typeid exception thrown" «endl;

I/... exit program or take other action here >

delete pa; return 0;

 

Программа отображает имена нескольких объектов. Рассмотрим подробнее следующие две строки, в кото­рых используется указатель ра на объект класса AnyClass:

cout «"Name: " «typeid(pa).nameO «endl; cout «"Name: " << typeid(*pa).name() << endl;

Оператор typeid корректно распознает ра как указатель типа AnyClass*. Он также корректно идентифици­рует разыменованный указатель *ра как объект типа AnyClass.

В следующей строке отображается Type_info — имя класса объекта, возвращаемое оператором typeid:

cout «"Name: " << typeid(typeid(i)).name() «endl;

Несомненная ошибка в Borland C++ не позволяет использовать функцию nameO в операторах вывода в поток обычным способом. Заключенный в комментарии участок листинга использует следующий оператор:

if (typeid(c)!= typeid(d))

cout «typeid(c).name() << " and "

<< typeid(d).name() «" are not equivalent." << endl;

Эти строки должны отображать сообщение "char and double are not equivalent", но вместо этого выводят "char and char are not equivalent". По неизвестным причинам второе использование функции nameO неверно идентифицирует вещественную переменную двойной точности d как имеющую символьный тип. Использова­ние двух отдельных операторов вывода в поток, похоже, помогает справиться с этой проблемой:

if (typeid(c)!= typeid(d)) {

pout << typeid(c).name() «" and ";

"cout «typeid(d).name() << " are not equivalent." << endl;

ЗАМЕЧАНИЕ

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

Резюме

• Друзья класса могут иметь доступ к закрытым, защищенным и, конечно, к открытым членам этого класса.

• Два класса могут объявляться друзьями друг друга. Такая взаимная дружба приводит к тому, что каждый из этих классов имеет доступ к закрытым и защищенным членам другого.

• Дружественные функции имеют доступ к закрытым и защищенным членам класса и могут быть обычными функциями C++ или членами класса.

• Перегрузка операторов расширяет типы данных, распознаваемые операторами C++. Вы можете перегружать как бинарные операторы, подобные делению (/) и умножению (*), так и унарные, такие как минус (-) и отрицание (-). За несколькими исключениями большинство операторов могут перегружаться, что позволяет определять действия для объектов класса в выражениях, использующих эти операторы.

• Поскольку new и delete — операторы, они также могут перегружаться для задания новых возможностей управления памятью для объектов класса.

• Обычно оператор new возвращает нуль, если невозможно выполнить запрос выделения памяти. Вы можете переопределить это действие с помощью вызова функции set_new_handler().

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

• В классах может перегружаться оператор присваивания, который вызывается, если один существующий объект присваивается другому, ранее объявленному объекту того же класса.

Потоки ввода-вывода реализованы классами, производными от класса ios, объявления которых содержатся в заголовочном файле IOSTREAM.H. Реализованы четыре объекта потоков ввода-вывода — cm, cout, cei и clog. В ios и производных от него классах определены операторы ввода («) и вывода (») в поток для всех встроенных типов данных C++.

Манипуляторы потоков ввода-вывода, объявленные в заголовочных файлах iomanip.h и iostreami позволяют форматировать ввод и вывод в потоковых операторах ввода-вывода. Вы также можете написать свои собственные манипуляторы.

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

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

Прочие средства C++, описанные в этой главе, включают в себя указатели на функции-члены, статически функции-члены, размещение объектов по заданным адресам, непосредственный вызов деструкторов инициализацию членов объекта класса, вложенные объявления классов и применение опции fast this.

Функция может возбуждать исключительную ситуацию, сигнализируя о возникновении исключительной условия. Обычно исключительные ситуации предназначены для сообщений об ошибках, но они Moryi иметь и другое применение. Для использования исключительных ситуаций на практике следует поместит функцию, возбуждающую исключительную ситуацию, в блок try, за которым должны следовать один или несколько операторов catch.

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

Если в программе возникли необработанные исключительные ситуации, то по умолчанию вызывается функция unexpectedO. Обычно функция unexpectedO вызывает функцию terminateO, которая, в свою очередь, вызывает функцию abort() для аварийного завершения программы. Вы можете заменить функции unexpectedO и terminateO своими функциями-обработчиками исключительных ситуаций. Заменить функцию abortO нельзя.

С помощью нового оператора typeid можно получить динамическую информацию о типе любого объекта.

Оператор возвращает объект класса Type_info, в котором описывается тип данных объекта. Вы также можете использовать оператор typeid для сравнения типов объектов.

Упражнения

15.1.Напишите код, моделирующий работу двигателя внутреннего сгорания. Придумайте два класса, один с именем TEngine (двигатель), другой с именем TFuel (горючее), в котором имеется закрытый веществен­ный член двойной точности level, показывающий сколько "горючего" залито в баки объекта класса. С помощью друзей объявите ваши классы так, чтобы класс TEngine имел непосредственный доступ к за­крытому члену level класса TFuel.

15.2.Добавьте функции перегрузки операторов умножения (*) и деления (/) в класс TStrOp в листинге 15.5.

15.3.Добавьте функции перегрузки операторов ++ и — в класс TStrOp в листинге 15.5. Реализуйте префиксные и постфиксные формы этих операторов.

15.4.Объявите и реализуйте оператор преобразования объекта класса TStrOp к типу double в листинге 15.5.

15.5.Дан класс с именем TFruit (фрукт) и объект orange (апельсин) типа TFruit, используйте orange для инициализации нового объекта с именем grapefruit (грейпфрут).

15.6.Напишите прототип для конструктора копирования гипотетического класса TFruit из упражнения 15.5.

15.7.Напишите перегруженный оператор присваивания для класса TFruit из упражнения 15.5.

15.8.Напишите программу, в которой используется шаблонная функция min() из листинга 15.10.

15.9.Создайте базу данных из 100 случайных целочисленных значений с помощью шаблонного класса TDatabase из листинга 15.12. С помощью цикла for и оператора вывода в поток отобразите значения объектов в 8-символьных столбцах.

 



Поделиться:


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

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