Иногда хочется проявить творчество и облегчить программный код для себя и для других. Для себя написание, для других понимание. Скажем, если в нашей программе часто встречается функция добавления одной строки в конец другой, конечно, можно это реализовать разными способами. А если мы, в каком-то участке нашего кода, напишем, к примеру так:
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
АААА…. Как написать символ конца строки?