Иногда хочется проявить творчество и облегчить программный код для себя и для других. Для себя написание, для других понимание. Скажем, если в нашей программе часто встречается функция добавления одной строки в конец другой, конечно, можно это реализовать разными способами. А если мы, в каком-то участке нашего кода, напишем, к примеру так:
char str1[15] = "Hello "; char str2[] = "world!"; str1 + str2;
и в результате получим строку «Hello world!». Правда, было бы замечательно? Ну так пожалуйста! Сегодня вы научитесь «объяснять» компьютеру, что оператором + вы хотите сложить не два числа, а две строки. И работа со строками — это один из самых удачных, на мой взгляд, примеров, чтобы начать разбираться с темой «Перегрузка операторов».
Приступим к практике. В этом примере мы перегрузим оператор + и заставим его к одной строке дописывать содержимое другой строки. А именно: мы соберем из четырех отдельных строк часть известного всем нам стиха А.С.Пушкина. Советую открыть вашу среду разработки и переписать этот пример. Если вам не все будет понятно в коде, не волнуйтесь, ниже будут приведены подробные объяснения.
#include <iostream>
#include <string.h>
using namespace std;
class StringsWork
{
private:
char str[256];//строка, которая доступна классу
public:
StringsWork()//конструктор в котором очистим строку класса от мусора
{
for(int i = 0; i < 256; i++) str[i] = '\0';
}
void operator +(char*);//прототип метода класса в котором мы перегрузим оператор +
void getStr();//метод вывода данных на экран
};
void StringsWork::operator +(char *s) //что должен выполнить оператор +
{
strcat(str, s); //сложение строк
}
void StringsWork::getStr()
{
cout << str << endl << endl;//вывод символьного массива класса на экран
}
int main()
{
setlocale(LC_ALL, "rus");
char *str1 = new char [strlen("У лукоморья дуб зелёный;\n")+1]; //выделим память для строк
char *str2 = new char [strlen("Всё ходит по цепи кругом;\n")+1];
char *str3 = new char [strlen("И днём и ночью кот учёный\n")+1];
char *str4 = new char [strlen("Златая цепь на дубе том:\n")+1];
strcpy(str1,"У лукоморья дуб зелёный;\n");//инициализируем
strcpy(str2,"Всё ходит по цепи кругом;\n");
strcpy(str3,"И днём и ночью кот учёный\n");
strcpy(str4,"Златая цепь на дубе том:\n");
cout << "1) " << str1;
cout << "2) " << str2;
cout << "3) " << str3;
cout << "4) " << str4 << endl;
StringsWork story;//создаем объект и добавяем в него строки с помощью перегруженного +
story + str1;
story + str4;
story + str3;
story + str2;
cout << "========================================" << endl;
cout << "Стих, после правильного сложения строк: " << endl;
cout << "========================================" << endl << endl;
story.getStr();
//Отмечу, что для числовых типов данных оператор плюс будет складывать значения, как и должен
int a = 5;
int b = 5;
int c = 0;
c = a + b;
cout << "========================================" << endl << endl;
cout << "a = " << a << endl << "b = " << b << endl;
cout << "c = " << a << " + " << b << " = " << c << endl << endl;
delete [] str4;//освободим память
delete [] str3;
delete [] str2;
delete [] str1;
return 0;
}
Разберемся:
Что-то новое в коде мы увидели в строке 16 void operator +(char*); Тут мы объявили прототип метода класса в котором перегрузим наш оператор +. Чтобы перегрузить оператор необходимо использовать зарезервированное слово operator. Выглядит это так, словно вы определяете обычную функцию: void operator+ () {//код} В теле этой функции мы размещаем код, который покажет компилятору, какие действия будет выполнять оператор + (или какой-либо другой оператор). Перегруженный оператор будет выполнять указанные для него действия только в пределах того класса, в котором он определен. Ниже, в строках 20 — 23 мы уже определяем какую роль будет играть + в нашем классе. А именно, с помощью функции strcat(str, s); он будет дописывать содержимое строки s , которую мы передали по указателю, в конец строки str. Строки 17, 25 — 28 это обычный метод класса, с помощью которого строка класса будет показана на экран. Если вам не понятно, как определять методы класса вне тела класса, т.е. такой момент как void StringsWork::getStr() {//определение}, то вам сначала желательно сходить сюда. Далее, уже в главной функции main(), в строках 34 — 37,создаем четыре указателя на строки и выделяем необходимое количество памяти для каждой из них, не забывая о том, что для символа '\0' так же надо зарезервировать одну ячейку char *str1 = new char [strlen("текст")+1];. Затем копируем в них текст с помощью функции strcpy() и показываем их на экран — строки 39 — 47. А в строке 49 создаем объект класса. При его создании сработает конструктор класса и строка класса будет очищена от лишних данных. Теперь нам остается только сложить строки в правильной последовательности, используя перегруженный оператор + — строки 50 — 53 и посмотреть, что получилось — строка 58.
Результат работы программы:
1) У лукоморья дуб зелёный;
2) Всё ходит по цепи кругом;
3) И днём и ночью кот учёный
4) Златая цепь на дубе том:
========================================
Стих, после правильного сложения строк:
========================================
У лукоморья дуб зелёный;
Златая цепь на дубе том:
И днём и ночью кот учёный
Всё ходит по цепи кругом;
========================================
a = 5
b = 5
c = 5 + 5 = 10
Ограничения перегрузки операторов
- перегрузить можно практически любой оператор, за исключением следующих:
. точка (выбор элемента класса);
* звездочка (определение или разыменование указателя);
:: двойное двоеточие (область видимости метода);
?: знак вопроса с двоеточием (тернарный оператор сравнения);
# диез (символ препроцессора);
## двойной диез (символ препроцессора);
sizeof оператор нахождения размера объекта в байтах;
- с помощью перегрузки невозможно создавать новые символы для операций;
- перегрузка операторов не изменяет порядок выполнения операций и их приоритет;
- унарный оператор не может использоваться для переопределения бинарной операции так же, как и бинарный оператор не переопределит унарную операцию.
Не забывайте, что в программировании очень желательно, делать все возможное, чтобы ваш код был как можно более понятным. Этот принцип касается всего: названий, которые вы даете переменным, функциям, структурам, классам, также и тех действий, которые будет выполнять перегруженный оператор. Старайтесь определять эти действия, как можно ближе к логическому значению операторов. Например + для сложения строк или других объектов класса, - для удаления строки и т.д.
Нельзя не отметить, что многие программисты негативно относятся к перегрузке операторов. Сама возможность перегрузки операторов предоставлена для облегчения понимания и читаемости кода программ. В то же время, она наоборот может стать и причиной усложнения вашей программы и многим программистам будет тяжело ее понять. Помните о «золотой середине» и используйте перегрузку только тогда, когда она реально принесет пользу вам и другим. Вполне можно обойтись и без перегрузки операторов. Но это не значит, что можно проигнорировать данную тему. В ней следует разобраться хотя бы потому, что вам когда-то придется столкнуться с перегрузкой в чужом коде и вы сможете легко разобраться что к чему.
Вот мы очень коротко ознакомились с перегрузкой операторов в С++. Увидели, так сказать, вершину айсберга. А вашим домашним заданием (ДА-ДА — ДОМАШНИМ ЗАДАНИЕМ!) будет доработать программу, добавив в нее перегрузку оператора для удаления строки. Какой оператор перегружать выберите сами. Либо предложите свой вариант апгрейда кода, добавив в него то, что посчитаете нужным и интересным. Ваши «труды» можете добавлять в комментарии к этой статье. Нам интересно будет посмотреть ваши варианты решения. Удачи!
Комментарии
Stanisław Pietkiewicz
АААА…. Как написать символ конца строки?