Лекции.ИНФО


При выполнении эта программа выводит такие результаты.



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;

}









Читайте также:

  1. A. Притяжения и отталкивания, силы отталкивания больше на малых расстояниях, чем силы притяжения. Б. Притяжения и отталкивания, силы отталкивания меньше на малых расстояниях, чем силы притяжения.
  2. Adjective and adverb. Имя прилагательное и наречие. Степени сравнения.
  3. B. 1. В США говорят по-английски. 2. Эта сумка сделана из кожи. 3. Окно разбито. 4. Владимир был построен в 10 веке. 5. Масло и сыр делают из молока. 6.Этот дом был построен моим дедом.
  4. D. Правоспособность иностранцев. - Ограничения в отношении землевладения. - Двоякий смысл своего и чужого в немецкой терминологии. - Приобретение прав гражданства русскими подданными в Финляндии
  5. D. ПРЕИМУЩЕСТВА ПРИСОЕДИНЕНИЯ К ГААГСКОМУ СОГЛАШЕНИЮ
  6. F70.99 Умственная отсталость легкой степени без указаний на нарушение поведения, обусловленная неуточненными причинами
  7. F71.98 Умственная отсталость умеренная без указаний на нарушение поведения, обусловленная другими уточненными причинами
  8. I Использование заемных средств в работе предприятия
  9. I ЭТАП (1-3 ст.) ОВОДНЕНИЕ ИКРИНКИ И ПОЯВЛЕНИЕ БЛАСТОДИСКА
  10. I этап. Теория рыночных структур (1880-1910 гг.)
  11. I. Методические принципы физического воспитания (сознательность, активность, наглядность, доступность, систематичность)
  12. I. О НОВОПРИБЫВШИХ ГРАЖДАНАХ.


Последнее изменение этой страницы: 2016-03-17; Просмотров: 97;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная