Основы программирования на С++ для начинающих

Перегрузка операторов в С++

Перегрузка операторов в какой-то степени творческий процесс. С её помощью, у программистов появляется возможность облегчить для себя написание кода, а для других – повысить читабельность. Например, когда какое-то действие приходится повторять в коде много раз, и просто мучительно постоянно использовать для этого специальные функции – можно перегрузить оператор для этого.

Допустим, в коде надо часто объединять  строки (дописывать строки  в строку элемент класса). Это можно оформить по-разному. Но мы сделаем так, чтобы объединение строк происходило тогда, когда мы используем оператор + :

Результатом этого должно стать изменение элемента  str. Он вместит в себе обе строки:  “Название нашего сайта PureCodeCpp”.

Пока мы явно не перегрузим оператор +, компилятор будет “ругаться”, так как мы складываем не числа, а  строки. Но сейчас мы научимся указывать ему, как надо действовать, когда мы просим выполнить нестандартное действие, используя  +.

Приступаем к практике. Определим в примере 4 строки. Далее соберем из них анекдот, объединив их в правильном порядке в одну строку.

Не будем говорить об очевидном – перейдем к разбору самой перегрузки. В строке 15 мы видим прототип метода класса Overload:   void operator +(char*);  Метод этот заставит работать оператор + так, как мы того захотим (так как мы определим ниже).  Чтобы перегрузить какой-либо оператор нужно использовать ключевое слово  operator.  В нашем случае, метод не возвращает значений поэтому void, далее ключевое слово operator и сам оператор +.  Принимает этот метод указатель на строку.

В строках 20 – 23 располагается определение метода перегрузки оператора. (Как определить метод вне класса читайте в статье Классы в С++) В нем, используя функцию  strcat_s(str, s); производится запись строки s  в конец строки str (элемент класса). Действует это так – как только в коде встретится оператор + за которым будет располагаться строка –  будет вызван метод перегрузки оператора и эта строка передастся в него по указателю.

В главной функции у нас определены в случайном порядке 4 строки. Отображаем их на экране (строки 39 – 42). Ниже, в строке 44, объявлен объект  Joke.  Во время его создания, конструктор класса, очистит элемент класса str от “мусора” и он будет готов для записи строк. Осталось выполнить простые действия (строки 46 – 49) – используя перегруженный + записать все строки в одну (str) в правильном порядке.

Результат:

перегрузка операторов c++,  перегрузка операций c++

Все получилось. Еще, как видно в результате, для числовых данных оператор + сработал правильно. Поэтому можно спокойно применять его для арифметических операций в коде – компилятор вас “поймет”. Еще один момент – перегрузка оператора действует только в пределах того класса, для которого она определена. Если мы определим еще один класс (Overload2 например) но не перегрузим для него оператор, то попытка использовать + для записи строки куда-либо приведет к ошибке.

Есть ряд исключений в С++ – не  все операторы можно перегрузить. Вот перечень:

перегрузка операторов c++,  перегрузка операций c++

И еще немного теории:

– перегрузка операторов не может изменить приоритет и порядок выполнения операций;

– нет возможности, с помощью перегрузки, создать новые символы для операций;

– бинарные операторы не могут быть использованы для переопределения унарной операции и наоборот – унарный оператор не переопределит бинарную операцию.

Перегрузка операторов, конечно,  “вещь” интересная. Только не стоит увлекаться. Используйте её только по мере острой необходимости – если это действительно будет приносить больше удобства, экономить вам время  и положительно скажется  на читабельности кода. Старайтесь перегружать операторы так, чтобы это было как можно ближе к их логическому  значению. То есть не надо складывать строки, перегружая оператор , например. Логичнее использовать +.

Отмечу, что многие программисты не очень любят перегрузку операторов, так как  некоторые чрезмерно ней увлекаются и читать код становится сложно. Так что внимательно взвешивайте все за и против, принимая решение о перегрузке операторов.

Я планирую в будущем написать еще одну статью о перегрузке операторов, где на примерах  хочу показать как перегрузить ++ инкремент, декремент, == равенство, = присваивание new и delete.

Дополнительно посмотрите видео по теме:

3 thoughts on “Перегрузка операторов в С++

  1. >> Например, когда какое-то действие приходится повторять в коде много раз, и просто мучительно постоянно использовать для этого специальные функции – можно перегрузить оператор для этого.

    В целом то верно, но перегрузка – это шикарный способ выстрелить себе в ногу (и еще отстрелить что-нибудь товарищу). Очень опасная штука. Она может как повысить читаемость кода, так и все испортить.

    У Маерса были правила на эту тему (если их не соблюдать – в аду вас заставят поддерживать свой код все 7 кругов). Например:
    – оператор присваивания должен возвращать ссылку на *this;
    – в операторе присваивания осуществляйте проверку самоприсваивания;
    – есть целыйел про перегрузку new и delete, но ИМХО 99% смертных просто не нужно трогать эти операторы;
    – объявляйте функции, не являющиеся членами, когда преобразование типов должно быть применимо ко всем параметрам.
    Ну и ряд других правил (в нескольких книжках).
    Предлагаю уделить внимание последнему правилу из списка. У вас описан оператор, который сработает для

    Joke + str1;
    Но не сработает для
    str1 + Joke;

    Но было бы здорово если оператор работал бы в обе стороны. Для этого достаточно сделать его не членом класса (обычной функцией). Это ведь совсем не сложно? )

  2. Visual Studio 2017 выдает ошибку на : char *str1 = “С лучезарным Челси на макушке.\n”;

    Ошибка C2440 инициализация: невозможно преобразовать “const char [32]” в “char *”

    – что где настроить нужно?

    И еще в каком-то уроке ошибка: Ошибка C3863 тип массива “bool [& n=’функция’+]” является неназначаемым на строке bool a[n = atoi(argv[1]) + 1];
    А в QT компилируется нормально (хотя синтаксис подсвечивает ошибку)

    1. Я обошел как: char *str1 = (char*)”С лучезарным Челси на макушке.\n”;
      И еще, разве не достаточно для очищения указать
      char str[256] = {}; //строка, которая вместит все строки

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *