Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
При выполнении эта программа выводит такие результаты.
2 25 Значение индекса 3 выходит за границы массива. При выполнении инструкции ob[3] = 44; операторной функцией operator[]() перехватывается ошибка нарушения границ массива, после чего программа тут же завершается, чтобы не допустить никаких потенциально возможных разрушений. Перегрузка оператора " ()" Возможно, самым интригующим оператором, который можно перегружать, является оператор " ()" (оператор вызова функций). При его перегрузке создается не новый способ вызова функций, а операторная функция, которой можно передать произвольное число параметров. Начнем с примера. Предположим, что некоторый класс содержит следующее объявление перегруженной операторной функции. int operator()(float f, char *p); И если в программе создается объект ob этого класса, то инструкция ob (99.57, " перегрузка" ); преобразуется в следующий вызов операторной функции operator(): operator() (99.57, " перегрузка" ); В общем случае при перегрузке оператора " ()" определяются параметры, которые необходимо передать функции operator(). При использовании оператора " ()" в программе задаваемые при этом аргументы копируются в эти параметры. Как всегда, объект, который генерирует вызов операторной функции (ob в данном примере), адресуется указателем this. Рассмотрим пример перегрузки оператора " ()" для класса three_d. Здесь создается новый объект класса three_d, координаты которого представляют собой результаты суммирования соответствующих значений координат вызывающего объекта и значений, передаваемых в качестве аргументов. // Демонстрация перегрузки оператора " ()". #include < iostream> using namespace std; class three_d { int x, y, z; // 3-мерные координаты public: three_d() { x = у = z = 0; } three_d(int i, int j, int k) {x = i; у = j; z = k; } three_d operator()(int a, int b, int c); void show(); }; // Перегрузка оператора " ()". three_d three_d:: operator()(int a, int b, int c) { three_d temp; temp.x = x + a; temp.у = у + b; temp.z = z + c; return temp; } // Отображение координат x, y, z. void three_d:: show() { cout < < x < < ", "; cout < < у < < ", "; cout < < z < < " "; } Int main() { three_d ob1(1, 2, 3), ob2; ob2 = ob1(10, 11, 12); // вызов функции operator() cout < < " ob1: "; ob1.show(); cout < < " ob2: "; ob2.show(); return 0; } Эта программа генерирует такие результаты. Ob1: 1, 2, 3 Ob2: 11, 13, 15 Не забывайте, что при перегрузке оператора " ()" можно использовать параметры любого типа, да и сама операторная функция operator() может возвращать значение любого типа. Выбор типа должен диктоваться потребностями конкретных программ. Перегрузка других операторов За исключением таких операторов, как new, delete, -> , -> * и " запятая" , остальные С++-операторы можно перегружать таким же способом, который был показан в предыдущих примерах. Перегрузка операторов new и delete требует применения специальных методов, полное описание которых приводится в главе 17 (она посвящена обработке исключительных ситуаций). Операторы -> , -> * и " запятая" — это специальные операторы, подробное рассмотрение которых выходит за рамки этой книги. Читатели, которых интересуют другие примеры перегрузки операторов, могут обратиться к моей книге Полный справочник по C++. Еще один пример перегрузки операторов Завершая тему перегрузки операторов, рассмотрим пример, который часто называют квинтэссенцией примеров, посвященных перегрузке операторов, а именно класс строк. Несмотря на то что С++-подход к строкам (которые реализуются в виде символьных массивов с завершающим нулем, а не в качестве отдельного типа) весьма эффективен и гибок, начинающие С++-программисты часто испытывают недостаток в понятийной ясности реализации строк, которая присутствует в таких языках, как BASIC. Конечно же, эту ситуацию нетрудно изменить, поскольку в C++ существует возможность определить класс строк, который будет обеспечивать реализацию строк подобно тому, как это сделано в других языках программирования. По правде говоря, " на заре" развития C++ реализация класса строк была забавой для программистов. И хотя стандарт C++ теперь определяет строковый класс, который описан ниже в этой книге, вам будет полезно реализовать простой вариант такого класса самим. Это упражнение наглядно иллюстрирует мощь механизма перегрузки операторов. Сначала определим " классовый" тип str_type. #include < iostream> #include < cstring> using namespace std; class str_type { char string[80]; public: str_type(char *str = " " ) { strcpy(string, str); } str_type operator+(str_type str); // конкатенация строк str_type operator=(str_type str); // присваивание строк // Вывод строки void show_str() { cout < < string; } }; Как видите, в классе str_type объявляется закрытый символьный массив string, предназначенный для хранения строки. В данном примере условимся, что размер строк не будет превышать 79 байт. В реальном же классе строк память для их хранения должна выделяться динамически, и это ограничение действовать не будет. Кроме того, чтобы не загромождать логику этого примера, мы решили освободить этот класс (и его функции-члены) от контроля выхода за границы массива. Безусловно, в любой настоящей реализации подобного класса должен быть обеспечен полный контроль за ошибками. Этот класс имеет один конструктор, который можно использовать для инициализации массива string с использованием заданного значения или для присваивания ему пустой строки в случае отсутствия инициализатора. В этом классе также объявляются два перегруженных оператора, которые выполняют конкатенацию и присваивание. Наконец, класс str_type содержит функцию show_str(), которая выводит строку на экран. Вот как выглядит код операторных функций operator+() и operator=(). // Конкатенация двух строк. str_type str_type:: operator+(str_type str) { str_type temp; strcpy(temp.string, string); strcat(temp.string, str.string); return temp; } // Присваивание одной строки другой. str_type str_type:: operator=(str_type str) { strcpy(string, str.string); return *this; } Имея определения этих функций, покажем, как их можно использовать на примере следующей функции main(). Int main() { str_type а(" Всем " ), b(" привет" ), с; с = а + b; с.show_str(); return 0; } При выполнении эта программа выводит на экран строку Всем привет. Сначала она конкатенирует строки (объекты класса str_type) а и b, а затем присваивает результат конкатенации строке c. Следует иметь в виду, что операторы " =" и " +" определены только для объектов типа str_type. Например, следующая инструкция неработоспособна, поскольку она представляет собой попытку присвоить объекту а строку с завершающим нулем. а = " Этого пока делать нельзя."; Но класс str_type, как будет показано ниже, можно усовершенствовать и разрешить выполнение таких инструкций. Для расширения круга операций, поддерживаемых классом str_type (например, чтобы можно было объектам типа str_type присваивать строки с завершающим нулем или конкатенировать строку с завершающим нулем с объектом типа str_type), необходимо перегрузить операторы " =" и " +" еще раз. Вначале изменим объявление класса. class str_type { char string{80]; public: str_type(char *str = " " ) { strcpy(string, str); } str_type operator+(str_type str); /* конкатенация объектов типа str_type*/ str_type operator+(char *str); /* конкатенация объекта класса str_type со строкой с завершающим нулем */ str_type operator=(str_type str); /* присваивание одного объекта типа str_type другому */ char *operator=(char *str); /* присваивание строки с завершающим нулём объекту типа str_type */ void show_str() { cout < < string; } }; Затем реализуем перегрузку операторных функций operator+() и operator=(). // Присваивание строки с завершающим нулем объекту типа str_type. str_type str_type:: operator=(char *str) { str_type temp; strcpy(string, str); strcpy(temp.string, string); return temp; } // Конкатенация строки с завершающим нулем с объектом типа str_type. str_type str_type:: operator+(char *str) { str_type temp; strcpy(temp.string, string); strcat(temp.string, str); return temp; } Внимательно рассмотрите код этих функций. Обратите внимание на то, что правый аргумент является не объектом типа str_type, а указателем на символьный массив с завершающим нулем, т.е. обычной С++-строкой. Но обе эти функции возвращают объект типа str_type. И хотя теоретически они могли бы возвращать объект любого другого типа, весь смысл их существования и состоит в том, чтобы возвращать объект типа str_type, поскольку результаты этих операций принимаются также объектами типа str_type. Достоинство определения строковой операции, в которой в качестве правого операнда участвует строка с завершающим нулем, заключается в том, что оно позволяет писать некоторые инструкции в естественной форме. Например, следующие инструкции вполне законны. str_type a, b, c; a = " Привет всем"; /* присваивание строки с завершающим нулем объекту */ с = а + " Георгий"; /* конкатенация объекта со строкой с завершающим нулем */ Следующая программа включает дополнительные определения операторов " =" и " +" . // Усовершенствование строкового класса. #include < iostream> #include < cstring> using namespace std; class str_type { char string[80]; public: str_type(char *str = " " ) { strcpy(string, str); } str_type operator+(str_type str); str_type operator+(char *str); str_type operator=(str_type str); str_type operator=(char *str); void show_str() { cout < < string; } }; str_type str_type:: operator+(str_type str) { str_type temp; strcpy(temp.string, string); strcat(temp.string, str.string); return temp; } str_type str_type:: operator=(str_type str) { strcpy(string, str.string); return *this; } str_type str_type:: operator=(char *str) { str_type temp; strcpy(string, str); strcpy(temp.string, string); return temp; } str_type str_type:: operator+(char *str) { str_type temp; strcpy(temp.string, string); strcat(temp.string, str); return temp; } Int main() { str_type а(" Привет " ), b(" всем" ), с; с = а + b; с.show_str(); cout < < " "; а = " для программирования, потому что"; а.show_str(); cout < < " "; b = с = " C++ это супер"; с = c + " " + а + " " +b; с.show_str(); return 0; } Популярное:
|
Последнее изменение этой страницы: 2016-03-17; Просмотров: 1216; Нарушение авторского права страницы