Ad hoc полиморфизм
Полиморфизм (polymorphism) — это способ присваивать различные значения (смыслы) одному и тому же сообщению. Смысл зависит от типа обрабатываемых данных. «Объектно-ориентированность» использует преимущества полиморфизма, привязывая поведение к типу объекта. Такие операторы, как + или « могут иметь различный смысл в зависимости от типов операндов.
Преобразование — это явное или неявное изменения типа значения. Преобразования представляют собой вид полиморфизма. Перегрузка функций придает функции с одним именем различные значения. Имя получает несколько интерпретаций, зависящих от выбора функции. Все это называется ad hoc полиморфизм. В этой главе обсуждается перегрузка, в особенности перегрузка операторов и преобразование типов данных.
Операторы перегружаются и выбираются на основе алгоритма соответствия сигнатуре. Перегрузка операторов придает им новые значения. Например, выражение а + b имеет различные значения, зависящие от типа переменных а и Ь. Перегрузка оператора + для определяемых пользователем типов дает возможность применять их в выражениях сложения почти таким же образом, как собственные типы. Выражение а + b может означать конкатенацию строк, сложение комплексных чисел или сложение целых, в зависимости от того, являются ли переменные абстрактными типами данных my_string или complex, или собственным типом int. Аналогично, благодаря функциям преобразования возможны выражения смешанных типов. В этой главе также обсуждаются дружественные функции (friend function), и почему они критичны для перегрузки операторов.
Один из принципов ООП состоит в том, что определяемые пользователем типы должны обладать теми же привилегиями, что и собственные типы. Клиент ожидает удобства при использовании таких типов, не обращая внимания на то, собственные они или нет. Способность производителя достичь такого результата является тестом на соответствие языка объектно-ориентированному применению. В базовом языке собственные типы могут смешиваться в выражениях, потому что это удобно. В противном случае было бы сложно определить привычные преобразования.
Преобразования атд
Явное преобразование типов в выражениях необходимо, если неявное преобразование нежелательно или если без такого преобразования выражение будет недопустимым. Одна из задач ООП на C ++ состоит в интеграции определяемых пользователем АТД и встроенных типов. Для этого существует механизм, позволяющий функциям-членам обеспечивать явные преобразования.
В предыдущей главе мы обсуждали, в каких случаях конструктор с одним аргументом фактически является преобразователем типа аргумента к типу класса конструктора.
my_string::my_string(const char* p);
Этот конструктор будет автоматически преобразовывать тип char* к типу my_string. Преобразование может быть как явным, так и неявным. Явно оно используется как операция преобразования в функциональной форме или в виде приведения. Так, и приведение
my_string s;
char* logo = "Рога и Копыта Лтд.";
s = static_cast<my_string>(logo);
и преобразование
s = logo; //неявный вызов преобразования
будут работать. Обратите внимание, что такое использование требует перегрузки оператора присваивания (см. раздел 7.7, «Перегрузка операторов присваивания и индексирования», стр. 202).
Здесь показаны преобразования уже определенного типа к пользовательскому типу. Однако пользователь не может добавить конструктор во встроенный тип, такой как int или double. С другой стороны, можно определить специальную функцию преобразования внутри класса. В общем виде подобная функция-член выглядит так
operator тип() { ••••• }
Данная функция-член должна быть нестатической. Она не может иметь параметры и не имеет объявленного возвращаемого типа. Она должна возвращать выражение указанного типа.
В примере с my_string может понадобиться преобразование my_string в char*. Это можно сделать следующим образом:
В файле string7.срр
my_string::operator char*()
{
char* p = new char[len +1];
assert(p != 0);
strcpy(p, s) ;
return p;
}
Заметьте, что мы не просто возвращаем значение закрытого члена s. Делая так, мы нарушили бы целостность объектов my_string.