Имеет ли смысл использовать const в интерфейсе или нет? - PullRequest
12 голосов
/ 28 декабря 2010

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

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 только что-то получает и ничего не меняет, поэтому я мог бы сделать это константой. И setValue, вероятно, изменяет данные, так что они не будут постоянными. Но для более общего метода, такого как уведомление, я не уверен.

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

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

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

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

Ответы [ 6 ]

5 голосов
/ 28 декабря 2010

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

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

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

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

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

4 голосов
/ 28 декабря 2010

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

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

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

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

2 голосов
/ 28 декабря 2010

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

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

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

void RecordCalculation(const ICalculationManager *calculation);

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

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

0 голосов
/ 28 декабря 2010

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

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

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

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

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

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

0 голосов
/ 28 декабря 2010

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

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

0 голосов
/ 28 декабря 2010

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

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

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

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

...