Мне нужно вызвать константную функцию из неконстантного объекта. См. Пример
struct IProcess {
virtual bool doSomeWork() const = 0L;
};
class Foo : public IProcess {
virtual bool doSomeWork() const {
...
}
};
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork {
getProcess().doSomeWork();
}
};
Звонок
getProcess().doSomeWork();
всегда приводит к вызову
IProcess& getProcess()
Есть ли другой способ вызвать
const IProcess& getProcess() const
из непостоянной функции-члена? Я до сих пор использовал
const_cast<const Bar*>(this)->getProcess().doSomeWork();
что делает свое дело, но кажется слишком сложным.
Обновлено: я должен упомянуть, что код реорганизуется, и в конечном итоге останется только одна функция.
const IProcess& getProcess() const
Однако в настоящее время существует побочный эффект, и вызов const может иногда возвращать другой экземпляр IProcess.
Пожалуйста, продолжайте тему.





Вам не нужно проделывать какие-либо уловки с кастингом, если функция не перегружена. Вызов константного метода неконстантного объекта - это нормально. Он вызывает неконстантный метод из объекта const, что запрещено. Если методы переопределены константной и неконстантной функцией, то приведение объекта к константе поможет:
const_cast<const IProcess&> (getProcess()).doSomeWork();
Обновлено: я не прочитал весь вопрос. Да, вам нужно преобразовать указатель это в const_cast или сделать функцию doOtherWork const для вызова const IProcess и getProcess () const.
Дело в том, что вам не нужен константный объект для вызова поработай немного. Поскольку это цель, нужен ли вам вызываемый метод const?
Другой вариант - переименовать замещаемые функции. Это было бы действительно хорошей идеей, если бы две функции действительно имели разное поведение / побочные эффекты. В противном случае эффект от вызова функции был бы не очевиден.
Есть ли побочные эффекты от функции getProcess? В противном случае какое значение имеет тот, который вызывается?
На самом деле, как указал mfazekas, в этом случае достаточно использовать static_cast <> вместо const_cast <>, поскольку вы добавляете, а не удаляете константность, что всегда является безопасной операцией.
Ну, ты можешь объявить
void doOtherWork const ()
?
Это сделало бы это.
К сожалению нет. doOtherWork () не должен быть постоянным.
Тогда может быть здесь неправильное решение. В чем разница между getProcess () const и plain? Это кеширование? Если так, официальное решение «изменяемое».
Вы в основном застряли с переименованием другого метода или const_cast.
Кстати, это одна из причин, по которой интеллектуальные указатели копирования при записи на самом деле не работают в C++. Интеллектуальный указатель копирования при записи - это тот, который может использоваться бесконечно. Когда пользователь обращается к данным в неконстантном контексте, создается копия данных (если у пользователя нет уникальной ссылки). Этот вид указателя может быть очень удобен при совместном использовании больших структур данных, которые нужно изменять только некоторым клиентам. Самая «логичная» реализация - иметь константный и неконстантный оператор->. Версия const просто возвращает базовую ссылку. Неконстантная версия выполняет уникальную проверку ссылок и копирование. Это бесполезно, потому что неконстантный умный указатель будет использовать неконстантный оператор-> по умолчанию, даже если вы хотите использовать константную версию. Требование const_cast делает его очень недружелюбным для пользователя.
Я приветствую всех, кто доказывает мою неправоту и показывает удобный для пользователя указатель копирования при записи на C++ ...
Ваше решение все равно не работает; smart_cow_ptr <T> не может знать, есть ли у T изменяемые члены.
Суть примера в том, что он не работает полезным образом. Если вы используете const_cast <smart_cow_ptr <T> &> (ptr) -> some_const_member (), он будет работать нормально, но требование выполнить const_cast IMHO делает использование указателя коровы слишком болезненным.
Я думаю, что метод const_cast - ваш лучший вариант. Это просто ограничение фреймворка const в C++. Я думаю, что единственный способ избежать кастинга - это определить метод, который независимо возвращает экземпляр const IProcess. Например.
const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
Если getProcess() и getProcess() const не возвращают ссылку на один и тот же объект (но с разной квалификацией), это указывает на плохую конструкцию class Bar. Перегрузка функции из-за const - не лучший способ различать функции с разным поведением.
Если они возвращают ссылку на тот же объект, тогда:
const_cast<const Bar*>(this)->getProcess().doSomeWork();
а также
getProcess().doSomeWork();
вызывать точно такую же функцию doSomeWork(), поэтому нет необходимости использовать const_cast.
«Копировать при записи» - это пример, когда константа / не константа может возвращать разные объекты, так что это не всегда плохой дизайн.
Я бы по-прежнему сказал, что перегрузка на const и возврат чего-либо, кроме прокси-класса, - плохой способ реализовать копирование при записи. Если что-то, что просто случайно имеет неконстантную ссылку, должно выполнить const_cast, чтобы избежать пессимистической копии, это часто будет упущено, и производительность будет страдать.
Я предполагаю, что вы хотите, чтобы DoOtherWork вызывал один из двух ваших вызовов getprocess в зависимости от того, вызывается он из объекта const или нет.
Лучшее, что я могу предложить:
class Bar
{
public:
const IProcess& getProcess() const {return ...;}
IProcess& getProcess() {return ...;}
void doOtherWork { // should use getProcess()
getProcess().doSomeWork();
}
void doOtherWork const {
getProcess().doSomeWork(); // should use getProcess() const
}
};
Даже если это сработает, мне кажется, это неприятный запах. Я бы очень опасался, что поведение класса радикально изменится в зависимости от константности объекта.
есть только одно определение каждого - void doOtherWork () - virtual bool doSomeWork () const
Posted by monjardin
Another option would be to rename the over-ridden functions. This would be a really good idea if the two function actually have different behavior/side-effects. Otherwise, the effect of the function call would not be obvious.
Доступ к IProcess & осуществляется в другом коде в основном через свойство
__declspec(property(get=getProcess)) IProcess& Process;
так что переименование было не вариант. В большинстве случаев constness вызывающей функции совпадает с getProcess (), поэтому проблем не было.
Избегайте приведения: назначьте это const Bar * или чему-то еще и используйте это для вызова getProcess().
Для этого есть несколько педантичных причин, но это также делает более очевидным то, что вы делаете, не заставляя компилятор делать что-то потенциально опасное. Конечно, вы можете никогда не попасть в эти случаи, но с таким же успехом можете написать что-нибудь, что в этом случае не использует приведение.
О каких педантичных доводах вы говорите? Я бы подумал, что большое уродливое приведение проясняет ваши намерения, чем присвоение const Bar *, но это только мое мнение.
Единственный способ, которым это имеет тенденцию вызывать неожиданное поведение, - это когда возвращаемое значение getProcess () изменяет свой квалификатор cv (т.е. становится изменчивым). Const_cast <> будет успешным, но он будет делать что-то совсем другое по сравнению с исходным намерением. Назначение поймает это. MSN
const_cast предназначен для приведения константности далеко!
Вы выполняете преобразование из неконстантного в константный, что безопасно, поэтому используйте static_cast:
static_cast<const Bar*>(this)->getProcess().doSomeWork();
Я имею в виду, что с технической точки зрения вы можете привести к константности с помощью const_cast, но это не прагматичное использование оператора. Цель приведений нового стиля (по сравнению со старым приведением стиля c) состоит в том, чтобы передать намерение приведения типов. const_cast - это запах кода, и его использование следует как минимум пересмотреть. static_cast с другой стороны безопасен. Но это вопрос стиля C++.
Или вы можете создать новый (частный) метод const и вызвать его из doOtherWork:
void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }
Также можно использовать временную константу (ответ «MSN»):
const Bar* _this = this;
_this->getProcess().doSomeWork();
На самом деле вы можете безопасно сделать и то, и другое - отбросить и добавить константность.
Да, но точка зрения mfazekas заключается в том, что вы используете только нужно const_cast <> для удаления константности, и в ваших собственных интересах использовать «наименьшее оружие, которое выполнит эту работу» (то есть static_cast <>), поскольку таким образом все вхождения const_cast это запахи кода, которые можно легко найти.
Если приведение слишком уродливо для вас, вы можете вместо этого добавить к Bar метод, который просто возвращает константную ссылку на *this:
Bar const& as_const() const {
return *this; // Compiler adds "const" without needing static_cast<>
}
Затем вы можете вызвать метод любойconst в Bar, просто добавив as_const()., например:
as_const().getProcess().doSomeWork();
определить шаблон
template< class T >
const T & addConst ( T & t )
{
return t;
}
и позвони
addConst( getProcess() ).doSomeWork();
Я пробовал это перед публикацией. К моему удивлению, неконстантная функция все равно была вызвана. Я еще раз подтвердю это в понедельник. Я работаю в MS VS6 - может быть проблема с компилятором. Спасибо за быстрый ответ.