Подтвердить что ты не робот

Имеет ли смысл использовать const в интерфейсе или нет?

У меня есть модуль, который выполняет некоторые вычисления и во время вычислений, общается с другими модулями. Поскольку модуль вычисления не хочет полагаться на другие модули, он предоставляет такой интерфейс (это, конечно, очень упрощенная версия):

class ICalculationManager
   {
   public:
      double getValue (size_t index) = 0;
      void setValue (size_t index, double value) = 0;
      void notify (const char *message) = 0;
   };

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

MyCalculationManager calcMgr;
CalculationTool calcTool (calcMgr);
calcTool.calculate();

Теперь мне интересно, имеет ли смысл добавлять "const" к методам интерфейса ICalculationManager.

Казалось бы логичным, что метод getValue получает только что-то и ничего не меняет, поэтому я могу сделать это const. И setValue, вероятно, изменяет данные так, чтобы они не были const. Но для более общего метода, такого как уведомление, я не могу быть уверен.

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

Мне кажется, что методы const имеют смысл только в том случае, если вы заранее знаете, какова будет ваша реализация и будет ли она const или нет. Это правда?

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

РЕДАКТИРОВАТЬ: изменил параметр от уведомления от "char *" до "const char *", поскольку это приводит к нерелевантным ответам.

4b9b3361

Ответ 1

Вы создаете функцию const, когда рекламируете клиентов, что вызов функции никогда не изменит внешне видимое состояние объекта. У вашего объекта есть только одно состояние, которое можно получить, getValue.

Итак, если getValue может привести к тому, что следующий getValue вернет другое значение, то обязательно оставьте его неконстантным. Если вы хотите сообщить клиентам, что вызов getValue() никогда не изменит значение, возвращаемое следующей getValue(), сделайте его const.

То же самое для уведомления:

double d1 = mgr->getValue(i);
mgr->notify("SNTH");  // I'm cheating.
double d2 = mgr->getValue(i);
assert(d1==d2);

Если это должно быть верно для всех случаев, и все i, то уведомлять() должно быть const. В противном случае это не должно быть.

Ответ 2

Да. Следует использовать const, когда и где это целесообразно. Не имеет смысла, что метод выполнения расчета (который предлагает ваш интерфейс) должен изменить его наблюдаемое поведение, потому что он "уведомлял" его об этом. (И в этом отношении, как уведомление связано с вычислением вообще?)

Мое создание одного из членов интерфейса const, вы не заставляете клиентов быть const - вы просто разрешаете им использовать const ICalculationManager.

Я бы, вероятно, сделал Notify const. Если клиентам необходимо что-то сделать non-const в результате уведомления, то Notify не является хорошим именем метода - это имя предлагает преобразования, не изменяющие состояние, такие как ведение журнала, а не изменение.

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

Ответ 3

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

Использование const - это способ сделать утверждения о том, что код или не разрешено делать. Это чрезвычайно полезно в рассуждении о части кода. Если ваш параметр notify не является const, какие изменения он внесет в сообщение? Как это сделать сообщение больше, если нужно?

Изменить: Кажется, вы знаете значение объявления параметра const, поэтому давайте об этом поработаем. Предположим, вы хотите, чтобы функция записывала значение вычисления:

void RecordCalculation(const ICalculationManager *calculation);

Единственными методами, которые вы сможете вызвать на этот указатель, являются методы const. Вы можете быть уверены, что после возвращения функции объект не изменится. Это то, что я имел в виду, рассуждая о коде - вы можете быть абсолютно уверены, что объект не будет изменен, потому что компилятор будет генерировать ошибку, если вы попытаетесь.

Изменить 2: Если ваш объект содержит какое-то внутреннее состояние, которое будет изменено в ответ на операции, которые являются логически const, например кеш или буфер, и используйте ключевое слово mutable тех членов. Это то, для чего оно было изобретено.

Ответ 4

Для меня это зависит только от контракта вашего интерфейса.

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

Для метода setter я согласен, а не const, потому что это как-то изменит данные.

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

Ответ 5

Без чтения всего сообщения: Да, конечно, имеет смысл, если вы хотите использовать объект (который наследует ICalculationManager) в контексте const. Как правило, вы всегда должны использовать конструктор const, если вы не манипулируете конфиденциальными данными.

EDIT: Как сказал Марк Рэнсом, вам нужно точно знать, как должны работать ваши функции интерфейса, иначе вы не закончили проектирование.

Ответ 6

Я знаю, что для этого я собираюсь получить много downvotes, но, на мой взгляд, полезность const-correctness в С++ сильно преувеличена. Идея const является примитивной (она только фиксирует один бит концепции... меняет/не изменяет) и поставляется с высокой стоимостью, что даже включает необходимость дублирования кода. Также он не масштабируется хорошо (рассмотрим const_iterators).

Что еще важнее, я не могу вспомнить ни одного случая (даже не ОДНОГО), в котором машина const-correctness помогла мне, обнаружив истинную логическую ошибку, то есть я пытался сделать то, чего я не должен был делать. Вместо этого каждый раз, когда компилятор остановил меня, возникла проблема в части объявления const (т.е. То, что я пытался сделать, было логически законным, но метод или параметр имел проблему в объявлении о const-ness). Во всех случаях я могу вспомнить, где я получил ошибку компилятора, связанную с const-correctness. Исправление было просто добавлением некоторых отсутствующих константных ключевых слов или удалением некоторых, которые были в избытке... без использования идеи const-correctness эти ошибки не были бы там вообще.

Мне нравится С++, но, конечно, я не люблю до смерти каждый его бит (отступление: когда я беру интервью у кого-то, вопрос, который я часто спрашиваю, "какая часть вам не нравится в <language> ?"... если ответ "нет", то просто означает, что тот, с кем я разговариваю, все еще находится в фанате фанатов и явно не имеет большого реального опыта).

Есть много частей С++, которые очень хороши, части, которые являются IMO ужасными (например, форматирование потока) и части, которые не ужасны, но ни логически красивы, ни практически полезны. Идея Const-correctness - это IMO в этой серой области (и это не впечатление новичка... Я пришел к такому выводу после многих строк и лет программирования на С++). Может быть, это я, но, по-видимому, правильность состязания решает проблему, которую не хватает моему мозгу... У меня много других проблем, но не из-за смущения, когда я должен изменить состояние экземпляра, и когда я этого не сделаю.

К сожалению (иначе, чем форматирование потока) вы не можете просто игнорировать механизм const-correctness на С++, потому что он является частью основного языка, поэтому, даже если мне это не нравится, я все равно вынужден его соблюдать.

Теперь вы можете сказать... хорошо, но какой ответ на вопрос? Это просто, что я не стал бы слишком сумасшедшим в отношении этой части семантического описания... это всего лишь один бит и поставляется с высокой ценой; если вы не уверены, и вы можете уйти без объявления константы, тогда не делайте этого. Константа ссылок или методов никогда не помогает компилятору (помните, что это может быть законно отброшено), и он был добавлен в С++, как помощь программистам. Мой опыт говорит мне, однако, что (учитывая высокую стоимость и низкий доход) это не реальная помощь вообще.