Является ли перегрузка операторов для обработки моих собственных классов как классов std хорошей практикой? - PullRequest
1 голос
/ 27 октября 2011

Я изучал основы Deitel C ++ и мр. Дейтель акцентирует внимание на перегрузке стандартных операторов, чтобы обеспечить стандартную функциональность для пользовательских классов и их членов. Я имею в виду, например, вместо cout << object.memberFunction(); Я могу просто сказать cout << object;

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

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

Ответы [ 5 ]

4 голосов
/ 27 октября 2011

Конечно, вы должны потратить некоторое время на изучение перегрузки оператора. Это, однако, не означает, что вы должны или не должны использовать перегрузку операторов. Но без обучения ты не сможешь решить. Решить использовать что-то, с чем вы не знакомы, сложно, если не невозможно. Вы всегда найдете что-то, что у вас нет знаний, с которым труднее в использовании, даже если это на самом деле проще.

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

1 голос
/ 27 октября 2011

Мне хочется сказать, что узнать об операторе нечего перегрузки; перегруженные операторы - просто забавные именованные функции. Какие Вы должны узнать, когда перегрузка уместна, и когда это не. Некоторые идиомы более или менее стандартны: числовые типы перегружаются соответствующие числовые операторы (+ и т. д.), перегрузка умных указателей указатель ops (* и ->), типы контейнеров, которые поддерживают индексацию перегрузка [], а перегрузка функциональных объектов (). И это о это для особых случаев. И хотя это, возможно, злоупотребление, если вы определить итератор, вы хотите, чтобы он поддерживал стандартный итератор идиома (что означает ++, *, -> и == / !=).

В дополнение к этому есть три оператора, которые будут перегружены для многих различных типов классов: назначение выполняется с использованием =, и вставка и извлечение из потоков осуществляется с помощью << и >>. Если вы хотите, чтобы ваш класс поддерживал любой из них, вы должны использовать перегрузки. И сравнение использует == и != для равенства и <, <=, > и >= для неравенства. Но не перегружайте из-за неравенства если это не семантически значимо. Лучше предоставить функция явного упорядочения для использования с std::map и std::set than вводить читателей в заблуждение, что вы определили их как семантически значительный порядок. Возможно, вы захотите специализировать std::less на вашем класс в этом случае; < не будет работать или будет иметь неправильную семантику для использования в качестве ключа, но std::less определит произвольный порядок который будет. И хотя это не перегрузка операторов, если тип использовать в качестве ключа в ассоциативных контейнерах, вы также хотите предоставить функция hash_code и экземпляр struct std::hash.

Во многих случаях лучше определить перегрузку в терминах еще нескольких глобальная функция: например: я использую compare (возвращая int меньше чем, равно или больше 0) для неравенства; Я определю общественность функция compare в классе, а затем получить из чего-то вроде:

template<typename T>
struct ComparisonOperators
{
    friend bool operator==( T const& lhs, T const& rhs )
    {
        return lhs.compare() < 0;
    }
    //  ...
    //  The same for the other five operators.
};

(Моя реализация на самом деле несколько сложнее, так как она использует метапрограммирование для использования isEqual для == и !=, если класс обеспечивает она.)

Я использую похожую технику для бинарных арифметических операторов, определяя + в терминах += и т. Д. Я также использую его для ввода-вывода, определяя << в терминах print и >> в пересчете на parse; это в основном полезно, когда операторы должны быть полиморфными.

1 голос
/ 27 октября 2011

Перегрузка оператора улучшает читабельность во многих случаях, и это те случаи, когда это полезно. Вероятно, у вас был неудачный пример в первый раз; это происходит, особенно с оператором <<, и вы узнали первый урок по перегрузке операторов: иногда явный вызов метода более понятен. Но иногда это не так. Для примера рассмотрим типичное матричное умножение в C ++ (например, с собственными матрицами): </p>

a = b * c;

и на Java:

a = b.multiplyUsingTheMatrixMultiplicationAlgorithmThatsMathYay(c);

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

0 голосов
/ 29 октября 2011

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

0 голосов
/ 27 октября 2011

Это обычная практика с использованием внешнего оператора друга для этой цели, что-то вроде

friend std::ostringstream & operator<<(std::ostringstream &oss, Type &type);

и

std::ostringstream & operator<<(std::ostringstream &oss, Type &type)
{
    oss << type.attr1;
    oss << type.attr2;
    oss << type.attr3;

    return oss;
}

, поэтому вы можете вызывать как:

Type val;
...
std::cout << val << std::end;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...