Являются ли перегрузки операторов в C ++ более сложными, чем они того стоят? - PullRequest
6 голосов
/ 01 апреля 2009

По моему опыту преподавания C ++, перегрузка операторов является одной из тех тем, которая вызывает наибольшее горе у студентов. Даже глядя на вопросы здесь в stackoverflow: например, сделать оператор + внешним или членом? Как справиться с симметрией и т. Д., Кажется, это много проблем.

Когда я переходил с C ++ на Java, я волновался, что упущу эту возможность, но, за исключением таких операторов, как [] или (), у меня никогда не возникало необходимости перегружать операторы. На самом деле, я чувствую, что программы без них более читабельны.

Примечание: я поставил это как вики сообщества. Давайте обсудим это. Я хочу услышать мнения.

Ответы [ 14 ]

0 голосов
/ 02 апреля 2009

Мне не хватает перегруженных операторов в Java, особенно в следующих ситуациях:

Класс, который является алгоритмом или функтором: (Шаблон стратегии, Цепочка ответственности, Интерпретатор и т. Д.). Естественно, перегрузка op (); вместо этого каждый программист придумывает (часто несовместимые и, таким образом, сбивающие с толку) имена для функций: «eval», «define», «operation», «doIt» и т. д. Таким образом, ясность уменьшается, потому что эти имена мы вынуждены использовать не делайте их смысл очевидным.

Класс, который имеет преобразование в другой тип: В C ++ это оператор Type (), который работает как для фактического преобразования, так и для получения внутреннего члена желаемого класса. Второй случай часто встречается в Java, когда класс неоправданно завершен, но вы хотите добавить к нему операции:

class DecoratedStringBuffer { //extends StringBuffer doesn't work, as String is final
  private String byContainmentThen;
  public decorate(final String prefix, final String suffix) { ... }
  public append(final String s) { byContainmentThen.append(s);}
  // other forwarding functions
}

Поскольку DecoratedStringBuffer не является StringBuffer, прежде чем он покинет ваш код и вернется к клиентскому коду, его необходимо преобразовать обратно, предположительно, с помощью функции, которая, наконец, применяет суффикс и префикс. Было бы здорово, если бы мы могли вызвать этот оператор StringBuffer () (и даже лучше, если бы Java, как и C ++, могла применить одно преобразование, предоставленное пользователем).

Вместо этого, поскольку нет соглашения, мы должны дать ему имя, которое обязательно будет более двусмысленным. getStringBuffer () - одно очевидное имя, но для многих пользователей Java это подразумевает соответствующий setStringBuffer, который нам не нужен. Даже если это не подразумевает этого, название неоднозначно: является ли StringBuffer тем, над которым мы работаем, или чем-то еще?

toStringBuffer () - лучшее имя, и шаблон, который я склонен применять, но затем кто-то, читающий код, задается вопросом, почему то, что выглядит как метод получения, называется "to" ClassName.

Честно говоря, кроме разработки числовых классов или "очевидно" совместимых объектов, для перегрузки op + мало что нужно. И поскольку Java не основана на значениях, как C ++, для op = нет особого смысла; Java не пытается заставить все действовать как примитивный класс значений int. Это op () и операторы преобразования, которые я пропускаю.

0 голосов
/ 02 апреля 2009

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

std::string str = "foo";
char *ch = str.c_str(); //rather than char *ch = str.operator *char();
0 голосов
/ 02 апреля 2009

Приятно иметь функцию, но не обязательно. Во многих случаях я нахожу их более запутанными, чем выгоды, которые они имеют. Как и в примере с JaredPars, функция .compare для меня более очевидна, чем «>». Прямо видно, что point1 - это объект, а не примитивный тип данных. Мне нравятся перегруженные операторы в библиотеках, которые я использую, но в своем собственном коде я использую их очень редко.

РЕДАКТИРОВАТЬ: мой выбор имени функции не соответствует. Замените .compare на .greaterThan, чтобы сделать его более понятным. Я имею в виду, что имя функции, привязанное к объекту, для меня более очевидно, чем оператор, не имеющий связи с объектом при первом взгляде. Имхо хорошо выбранное имя функции легче читать.

0 голосов
/ 02 апреля 2009

Проблема с перегрузкой операторов заключается в том, что некоторым людям нравится перегружать их функциональностью, которая на самом деле не имеет никакого смысла в отношении первоначальной (C) цели оператора (здесь я указываю на операторы >> и << в материале std :: iostream.). На мой взгляд, единственный раз, когда вы должны перегрузить операторы, это когда перегрузка ТОЧНО совпадает со значением основного оператора (т. Е. <И> должны быть сравнениями.) ИЛИ вы должны перегрузить его определенным образом, чтобы взаимодействовать с другим библиотека.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...