Вызов постоянной функции из неконстантного объекта

StackOverflow https://stackoverflow.com/questions/407100

  •  03-07-2019
  •  | 
  •  

Вопрос

Мне нужно вызвать 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 ++...

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top