Как вызвать неконстантную функцию внутри константной функции (C++)

У меня есть устаревшая функция, которая выглядит так:

int Random() const
{
  return var_ ? 4 : 0;
}

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

int Random() const
{
  return var_ ? newCall(4) : 0;
}

Проблема в том, что я получаю эту ошибку:

In member function 'virtual int Random() const':
class.cc:145: error: passing 'const int' as 'this' argument of 'int newCall(int)' discards qualifiers

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

Мой вопрос: есть ли способ вызвать функцию в Random(), которая не является константой? Или у кого-нибудь есть идеи о том, как реализовать newCall() в Random(), не делая половину моей программы константой.

Спасибо

-Джош


person Grammin    schedule 15.02.2011    source источник
comment
Вы можете сделать Random() неконстантным.   -  person GWW    schedule 15.02.2011
comment
Я бы хотел, но Random() - это устаревший код, который я не могу трогать.   -  person Grammin    schedule 15.02.2011
comment
Это 4, выбранные беспристрастным кубиком (что делает его действительно случайным).   -  person Martin York    schedule 15.02.2011
comment
глядя на сообщение об ошибке, я блуждаю, возможно, ваша проблема в другом? Обратите внимание на передачу const int как this. Звучит странно, возможно, аргумент 4 интерпретируется как this? Зачем?   -  person davka    schedule 15.02.2011
comment
Вопрос не в том, сколько функций нужно будет объявить const, а в том, являются ли эти функции на самом деле const: изменяют ли они какие-либо члены объекта? Если нет, то пометьте их как const.   -  person David Rodríguez - dribeas    schedule 15.02.2011


Ответы (7)


вы должны изменить свою программу, чтобы использовать/объявить const правильно...

одной из альтернатив является использование const_cast.

person justin    schedule 15.02.2011
comment
Неправильное использование const_cast (а именно это и произойдет) приведет к полной катастрофе. - person Martin York; 15.02.2011
comment
Спасибо за совет, в итоге я изменил функции ниже newCall() и newCall(), чтобы все они были константными, потому что я не хотел использовать константу неправильно. - person Grammin; 15.02.2011
comment
@Grammin всегда пожалуйста. правильное объявление имеет много преимуществ. самое важное (imo) заключается в том, что это экономит массу времени при обслуживании и удобочитаемости. компилятор может быстро обнаружить неправильное использование при изменении программы. побочным эффектом является то, что С++ начинает писать так много констант, что вы думаете, что было бы неплохо, если бы константа была значением по умолчанию в некоторых случаях, и чтобы вместо этого использовалось ключевое слово для указания мутации :) - person justin; 15.02.2011
comment
Есть еще один способ, через прокси. stackoverflow.com/questions/8325400/ - person Janosimas; 05.05.2015
comment
одной из альтернатив является использование const_cast.... Как они должны использовать const_cast? - person Vaillancourt; 27.06.2017
comment
@AlexandreVaillancourt Суть, которую я подчеркиваю в своем ответе, заключается в том, что вы должны изменить свою программу, чтобы правильно использовать/объявить const... Использование const_cast в сценарии OP является альтернативой, которую можно использовать для удаления const из this. Вывод, который я сделал 6 лет назад (и сегодня), заключается в том, что вы не должны использовать const_cast для выполнения этого, потому что а) это будет запутанно и неправильно и б) это может привести к неопределенному поведению. Хорошие примеры использования const_cast — это введение const или изменение квалификаторов const, volatile, __unaliged (если вы знаете, что это безопасно и законно). - person justin; 04.08.2017
comment
@AlexandreVaillancourt Если вам просто нужен пример использования, вот он: docs .microsoft.com/en-us/cpp/cpp/const-cast-operator — по возможности избегайте стирания const и понимайте, что квалифицируется как UB. Конечно, const_cast превосходит приведение в стиле C - когда вам (действительно) это нужно. Случаи, когда вам это нужно, должны быть довольно редкими при работе с хорошо написанными современными API. В основном я использую его при работе с C API. К счастью, мне не приходится им часто пользоваться. Наконец, строка, которую я не рекомендую, будет выглядеть так: return var_ ? const_cast<TYPE*>(this)->newCall(4) : 0;. - person justin; 04.08.2017

int Random() const
{
  return var_ ? const_cast<ClassType*>(this)->newCall(4) : 0;
}

Но это не очень хорошая идея. Избегайте, если это возможно!

person Nawaz    schedule 15.02.2011
comment
Как вы сказали, если вам действительно нужно использовать const_cast для достижения этой цели, попробуйте реорганизовать свой дизайн. - person thatWiseGuy; 17.02.2016
comment
иногда ничего не поделаешь.. предыдущий программист перепроектировал, использовал все причудливые функции языка, а затем покинул компанию после того, как его код стал слишком грязным и неудобным в сопровождении.. - person Zennichimaro; 28.09.2018
comment
Наконец-то разумный ответ вместо «вы не должны этого делать»… Всегда есть ситуации, когда вы должны или даже поощряетесь. Например, что делать, если вы хотите предоставить константный метод интерфейса и использовать ту же логику для неконстантной реализации? Например, представьте себе логику хождения по дереву. Следует ли скопировать его для написания константных методов доступа и неконстантных методов доступа для всех узлов? Или просто создайте чистые константные и неконстантные оболочки для этих задач? - person avtomaton; 17.09.2020

const_cast<MyClass *>(this)->newCall(4)

Делайте это только в том случае, если вы уверены, что newCall не изменит «это».

person Erik    schedule 15.02.2011

Здесь есть две возможности. Во-первых, newCall и ВСЕ ее вызываемые функции на самом деле являются немодифицирующими функциями. В этом случае вы обязательно должны пройти и отметить их все const. И вы, и будущие сопровождающие кода будут вам благодарны за облегчение чтения кода (из личного опыта). Во-вторых, newCall фактически изменяет состояние вашего объекта (возможно, через одну из функций, которые он вызывает). В этом случае вам нужно сломать API и сделать Random неконстантным, чтобы правильно указать вызывающим, что он изменяет состояние объекта (если модификации влияют только на физическую константность, а не на логическую константность, вы можете использовать изменяемые атрибуты и распространять const).

person Mark B    schedule 15.02.2011

Не могли бы вы попробовать создать новый экземпляр класса в методе Random() без использования константных приведений?

person Coffee on Mars    schedule 15.02.2011

Квалификатор const утверждает, что экземпляр this класса не изменится после операции, что компилятор не может вывести автоматически.

const_cast можно использовать, но это зло

person Foo Bah    schedule 15.02.2011

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

person justin    schedule 15.02.2011
comment
Это не генератор случайных чисел, мне просто нужен пример для SO. Однако, спасибо - person Grammin; 15.02.2011