Вызов постоянной функции из неконстантного объекта
Вопрос
Мне нужно вызвать const-функцию из неконстантного объекта.Смотрите пример
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 Bar *
или что-то еще и используйте это для вызова getProcess()
.
Есть несколько педантичных причин для этого, но это также делает более очевидным то, что вы делаете, не заставляя компилятор делать что-то потенциально небезопасное.Конечно, вы, возможно, никогда не столкнетесь с этими случаями, но с таким же успехом вы могли бы написать что-то, что не использует приведение в данном случае.
Другие советы
const_cast
предназначен для литья прочь постоянство!
Вы переходите от неконстантного значения к const, что безопасно, поэтому используйте static_cast
:
static_cast<const Bar*>(this)->getProcess().doSomeWork();
Я имею в виду, с технической точки зрения, вы можете использовать constness с помощью const_cast
, но это не прагматичное использование оператора.Цель приведений в новом стиле (по сравнению со старым приведением в стиле c) - передать намерение приведения. const_cast
это запах кода, и его использование должно быть, по крайней мере, пересмотрено. static_cast
с другой стороны, это безопасно.Но это вопрос стиля C ++.
Или вы можете создать новый (частный) метод const и вызвать его из doOtherWork
:
void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }
Использование const temporary также является вариантом (ответ "MSN").:
const Bar* _this = this;
_this->getProcess().doSomeWork();
Если getProcess()
и getProcess() const
не возвращают ссылку на один и тот же объект (но с другой квалификацией), то это указывало бы на плохой дизайн class Bar
.Перегрузка на const
наличие функции не является хорошим способом различения функций с различным поведением.
Если они возвращают ссылку на один и тот же объект, то:
const_cast<const Bar*>(this)->getProcess().doSomeWork();
и
getProcess().doSomeWork();
звоните точно так же doSomeWork()
функция, поэтому нет необходимости использовать 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();
Вам не нужно выполнять никаких трюков с приведением, если функция не перегружена.Вызов метода const неконстантного объекта - это нормально.Это вызов неконстантного метода из объекта const, который запрещен.Если методы переопределены с помощью const и неконстантной функции, то приведение объекта к const сделает свое дело:
const_cast<const IProcess&> (getProcess()).doSomeWork();
Редактировать:Я не прочитал вопрос целиком.Да, вам нужно выполнить const_cast для это указатель или сделать Выполняйте другую работу функция const для вызова const iProcess& getProcess() const.
Суть остается в том, что вам не нужен объект const для вызова Домашняя работа.Поскольку это и есть цель, нужен ли вам вызываемый метод const?
Другим вариантом было бы переименовать перегруженные функции.Это было бы действительно хорошей идеей, если бы две функции на самом деле имели разное поведение / побочные эффекты.В противном случае эффект от вызова функции был бы неочевиден.
определите шаблон
template< class T >
const T & addConst ( T & t )
{
return t;
}
и позвонить
addConst( getProcess() ).doSomeWork();
Ну, можете ли вы заявить
void doOtherWork const ()
?
Это сделало бы это.
Я думаю, что метод const_cast - ваш лучший вариант.Это всего лишь ограничение фреймворка const в C ++.Я думаю, единственный способ избежать приведения - это определить метод, который независимо возвращает экземпляр const iProcess.Например.
const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();
Я предполагаю, что вы хотите, чтобы 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
}
};
Даже если это сработает, мне кажется, что это неприятно пахнет.Я бы очень опасался радикального изменения поведения класса в зависимости от постоянства объекта.
Автор : монжарден
Другим вариантом было бы переименовать перегруженные функции.Это было бы действительно хорошей идеей, если бы две функции на самом деле имели разное поведение / побочные эффекты.В противном случае эффект от вызова функции был бы неочевиден.
iProcess& доступен в другом коде в основном через свойство
__declspec(property(get=getProcess)) IProcess& Process;
так что переименование было не вариантом.Большую часть времени постоянныйкачество вызывающей функции соответствует getProcess(), так что проблем не возникло.
По сути, вы застряли с переименованием другого метода или const_cast .
Кстати, это одна из причин, по которой интеллектуальные указатели копирования при записи на самом деле плохо работают в C ++.Интеллектуальный указатель копирования при записи - это тот, которым можно делиться бесконечно.Когда пользователь обращается к данным в неконстантном контексте, создается копия данных (если у пользователя нет уникальной ссылки).Этот тип указателя может быть очень удобен в использовании при совместном использовании больших структур данных, которые необходимо изменять только некоторым клиентам.Наиболее "логичной" реализацией является наличие const и неконстантного оператора->.Const версия просто возвращает базовую ссылку.Неконстантная версия выполняет проверку уникальной ссылки и копирование.Это бесполезно, потому что неконстантный интеллектуальный указатель будет использовать неконстантный оператор-> по умолчанию, даже если вы хотели использовать const версию.Требование const_cast делает его очень недружелюбным к пользователю.
Я приветствую любого, кто докажет мою неправоту и покажет удобный указатель копирования при записи на C ++...