Полиморфизм – средство для придания различных значений одному и тому же сообщению в зависимости от типа обрабатываемых данных.
Преобразование – это явное или неявное изменение значения в зависимости от типа. Преобразования обеспечивают форму полиморфизма.
Перегрузка функций дает одному и тому же имени функции различные значения. Одно и то же имя имеет различные интерпретации, которые зависят от выбора функции. Выбранная функция удовлетворяет алгоритму соответствия сигнатур для C++. Такая форма полиморфизма называется (ad hoc) специальным полиморфизмом. Эта глава, в основном, посвящена перегрузке, в первую очередь -перегрузке оператора и преобразованию типов данных.
Операторы перегружаются и выбираются на основании алгоритма соответствия сигнатур. Перегрузка операторов придает им новые значения. Например, выражение а + b имеет различные значения, в зависимости от типов переменных а и b. Перегрузка оператора + для типов, определяемых пользователем, позволяет использовать их в дополнительных выражениях в большинстве случаев так же, как и встроенные типы. Выражение а + b может означать конкатенацию строк, сложение комплексных или целых чисел в зависимости от того, какими были переменные — АТД string, АТД complex или встроенного типа int. При определении функции преобразования допустимы также выражения смешанного типа. Кроме того, в этой главе обсуждаются friend-функции и то, насколько они важны для перегрузки операторов.
Один из принципов ООП состоит в том, что определяемые пользователем типы должны иметь те же привилегии, что и встроенные типы. Пользователю необходимо одинаковое удобство при использовании как встроенных, так и внешних типов. Чем точнее изготовитель достигает такого результата, тем адекватнее язык ООП использованию. Типы, встроенные в базовый язык, могут смешиваться в выражениях, поскольку это удобно, но, с другой стороны, при этом обременительно определять последовательность необходимых преобразований.
Преобразования, определяемые классом
Явное преобразование типов выражения применяется тогда, когда неявное преобразование нежелательно или когда без него выражение недопустимо. Одна из задач C++ – интеграция АТД и встроенных типов. Чтобы достигнуть этого, существует механизм функции-члена, обеспечивающей явное преобразование.
Функциональная запись в такой форме
Имя типа (выражение)
эквивалентна приведению. Тип должен быть выражаем как идентификатор. Таким образом, два выражения
х = float(i); //функциональная запись C++ х = (float) i;
эквивалентны. Выражение
р = (int*) q; //допустимое приведение
не может непосредственно функционально выражаться как
р = int* (q); //запрещено
Однако, для этого может использоваться typedef.
typedef int* int_ptr;
р = int_ptr (q) ;
Поэтому функциональная запись более предпочтительна. Конструктор с одним аргументом фактически представляет собой преобразование из типа аргумента к типу конструируемого класса. В разделе 6.4
строковый тип имел такой конструктор:
string (const char* р)
{len=strlen(p);
s=new char[len+1];
strcpy(s,р);
}
Конструкторы как преобразования
Конструкторы с одиночным параметром автоматически являются функциями преобразования. Преобразования представляют собой аспект полиморфизма (см. главу 7) и упрощают код пользователя. Проанализируем следующий класс, цель которого состоит в том, чтобы печатать невидимые символы с их обозначением ASCII; например, код 07 (восьмеричный) signal или bel.
//печатные символы ASCII
class pr_char
{private:
int c;
static char* rep[128];
public:
pr_char(int i = O): c(i % 128) {}
void print() { cout<
char* pr_char::rep[128]={"nul","soh","stx",// и т. д.
...
"w", "x", "у", "z", "{", "|",")","~", "del"};
main()
{int i;
pr char c;
for (i = 0; i < 128; ++i ) {
c = i; // так же с = pr char(i ); или с = (pr char)i;
c.print() ;
cout<
} }
Конструктор выполняет автоматическое преобразование из целых чисел в pr char. Это делается с помощью оператора
с = i;
в цикле. Возможно использовать и явное приведение. Чрезмерное применение неявньк преобразований может привести к написанию небезопасного кода неизвестного типа.
Преобразованиям посвящен материал главы 7. Одна из причин того, что ООП требует использования преобразований, состоит в том, что типы, определяемые пользователем, должны выглядеть и ощущаться как встроенные типы.
Представленное выражение — автоматическое преобразование типа от char* к string. Оно доступно как явно, так и неявно. Явно оно используется или как операция преобразования, или в приведении, или в функцио-нальной форме. Таким образом, возможны два рабочих варианта кода:
string s;
char* logo = “Geometries Inc” ;
s=string(logo); //выполняет преобразование, затем присвоение
И
s = logo; //неявный вызов преобразования
Данный код – преобразование из уже определенного типа к типу, определяемому пользователем. Однако, пользователь не может добавлять конструкторы встроенных типов, таких как int или double. В примере со строкой может возникнуть необходимость в преобразовании из строки в char*, что может быть выполнено с помощью определения специальной функции преобразования внутри класса string следующим образом:
operator char*(){return (s);}
Общая форма записи такой функции-члена:
operator тип{) {. . .}
Такая функция преобразования должна быть нестатической функцией-членом без возвращаемого типа и с пустым списком аргументов. Преобразования происходят неявно в выражениях присвоения, при передаче параметров функциям, и в значениях, возвращаемых функциями.
Преобразующая функция-член в форме А::operatorВ() и конструктор в форме В::В(const A&) обеспечивают преобразование из типа объекта А в тип объекта В. Наличие обоих одновременно может приводить к ошибкам неоднозначности.
Похожие записи
No user прокомментировали сообщение
Оставить комментарий