    58:	     cout « "Name : " « typeid(*p).name() «	endl ; 
    59:	     cout « "Borland C++ bug. This SHould not	appear. " « endl; 
    60:	     p = new int; // Never executes 
    61:	     delete p;   // Never executes
    62:	  } 
    63:	  catch (Bad_typeid x) { 
    64:	     cout « "Error: typeid exception thrown"	« endl; 
    65:	      // . . . exit program or take other action	here 
    66:	  } 
    67: 
    68:	  delete pa; 
    69:	  return 0; 
    70:	} 

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

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

   Оператор typeid корректно распознает ра как указатель типа AnyClass*. 
Он также корректно идентифицирует разыvенованный указатель *ра как объект типа AnyClass. 
    В следующей строке отображается Type_info — имя класса объекта, 
возвращаемое оператором typeid: 

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

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

    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". По 
неизвестным причинам второе использование функции name() неверно идентифицирует 
вещественную переменную двойной точности d как имеющую символьный тип. 
Использование двух отдельных операторов вывода в поток, похоже, помогает 
справиться с этой проблемой: 

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


    ЗАМЕЧАНИЕ 
    
    Динамическая идентификация типов   —  совершенно новая технология. Пока 
не устранены все ошибки, следует пользоваться ей острожно.


    Резюме 

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

    Глава 15. Передовые средства C++ 421 
