Перегрузка оператора ++ префикс / постфикс с точки зрения друг друга? - PullRequest
3 голосов
/ 14 июля 2010

У меня есть вопрос, на который можно было ответить более 9000 раз, но я действительно не знаю, как это выразить, вот что я собираюсь попробовать.

Я видел в некоторых книгах и руководствах по C ++, что при определении собственного класса, который имеет семантику итеративных значений (с приращением), вы можете перегрузить operator++ для этого (все, что я собираюсь здесь изложить, я думаю, относится и к operator--). Стандартный способ сделать это выглядит так:

class MyClass {
    public:
    MyClass& operator++ () {
        increment_somehow();
        return *this;
        }
    ....
    };

Где increment_somehow() ну ... как-то увеличивает значение объекта.

Тогда можно определить постфиксную версию operator++ таким образом:

MyClass operator++ (MyClass& it, int dummy) {
    MyClass copy(it);
    ++it;
    return copy;
    }

Все хорошо и прекрасно (я думаю, что я правильно понял эту идиому), но проблема в том, что выполнение всего этого для каждого класса, который определяет operator++, быстро становится утомительным и многословным, поэтому я подумал, что могу взять немного Преимущество трюка, который я недавно узнал при перегрузке операторов. То есть, используя заголовок <utility> и средство под названием rel_ops, о котором я узнал вчера (я только что вернулся на C ++ после четырех лет отсутствия ...):

class MyClass {
    public:
    bool operator== (const MyClass& that) {
        return compare_for_equality_somehow(that);
        }
    bool operator< (const MyClass& that) {
        return compare_for_lessality_somehow(that);
        }
    ....
    using namespace std::rel_ops; // operators >, >=, <=, ! are "magically" defined!
    };

(Я только что изобрел термин «меньшинство» для целей аналогии, моя голова почему-то отказывается придумать правильный математический термин ...)

Я создал простой заголовок <step_ops.hpp>, содержимое которого несколько имитирует пространство имен std::rel_ops, найденное в заголовке Utility. Что я вижу после нескольких компиляций, это просто работает (ТМ). Могу ли я / я должен использовать этот трюк? С какими возможными ловушками я мог бы столкнуться, если бы я создал класс и использовал using namespace MyLibrary::increment_operators (например)?

И, может быть, намного, гораздо важнее: Я только что заново изобрел колесо или просто создал небольшую полезную библиотеку, которая может быть объединена для подобных проектов ? Практически все эксперименты, которые я пытался провести с C ++, чтобы вернуть себя к скорости и совместной работе, похоже, уже покрыты boost::do_something возможностью, и мне немного грустно, что я провел так много времени .

Ответы [ 4 ]

4 голосов
/ 14 июля 2010

Boost предоставляет эту функцию в служебной библиотеке Boost Operators . Его реализация немного отличается, но достигает того же результата.

Могу ли я / я должен использовать этот трюк?

Используйте его везде, где можете; Вырезание избыточного и повторяющегося кода является фундаментальным принципом рефакторинга и является хорошей практикой.

Я просто заново изобрел колесо или просто создал полезную небольшую библиотеку, которая может быть объединена для подобных проектов?

Полагаю, вы могли бы сказать, что заново изобрели колесо. Однако я не думаю, что это обязательно плохо: я обнаружил, что, если я сам что-то реализую, я обычно понимаю это намного лучше и многому учусь в процессе.

1 голос
/ 14 июля 2010

Если у вас есть время, чтобы сэкономить, и вам нужен опыт, заново изобретите все колеса, которые вам нравятся. Я сделал несколько сам, чтобы улучшить мои знания основных концепций. Это может очень помочь.

0 голосов
/ 11 августа 2010

Я оригинальный постер, просто отвечая, чтобы сказать, что я наконец-то зарегистрировался в StackOverflow. Таким образом, у меня есть новая ручка. Теперь говорю спасибо за ответы, в частности HeadGeek с вопросом мотивации. Кроме того, чтобы исправить себя и следовать комментариям tjm, точная форма кода используется не так, как я написал. Более правильный способ использования этого метода - перенести каждый оператор в собственную область видимости класса через using:

namespace scope {
class MyClass {
  public:
  bool operator== (const MyClass& that) {
    return compare_for_equality_somehow(that);
    }
  bool operator< (const MyClass& that) {
    return compare_for_lessality_somehow(that);
    }
  ....
  // using namespace std::rel_ops; // that one is incorrect
  };
using std::rel_ops::operator=!; // similarly for >, >=, <=
} // end of namespace

Если это сделано, как в моем первоначальном посте, заголовок компилируется нормально, но ошибки компиляции возникают, когда заголовок включен в проект, который также включает и использует rel_ops где-то. Что еще более важно, этот метод принесет все операторы для всех классов, определенных в области видимости класса - определенно нежелательно. При таком подходе в явном виде using в область действия включаются только необходимые операторы, и они разрешаются по мере необходимости.

Спасибо всем, скоро увидимся.

( Также, пожалуйста, не задавайте этот вопрос, если вы действительно не чувствуете, что он может что-то предложить - в этом нет ничего нового, поскольку у Boost это уже есть - я опубликовал это в двух информативных целях )

0 голосов
/ 14 июля 2010

В качестве альтернативы вы можете использовать <template T>, он встроен прямо в язык c ++, он позволяет вам использовать несколько типов для одного и того же кода, все что вам нужно сделать, это убедиться, что для каждого класса, который использует вновь определенный операторс классом template все методы определены.

См. документацию для получения дополнительной информации о template http://www.cplusplus.com/doc/tutorial/templates/

...