Подтвердить что ты не робот

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

Мне нужно вызвать функцию 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 некоторое время.

Пожалуйста, продолжайте тему.

4b9b3361

Ответ 1

Избегайте приведения: присвойте это const Bar * или тому подобное и используйте для вызова getProcess().

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

Ответ 2

const_cast предназначен для создания прочь константы!

Вы выполняете отличную от константы константу, которая является безопасной, поэтому используйте static_cast:

   static_cast<const Bar*>(this)->getProcess().doSomeWork();

Я имею в виду технически говорящий, который вы можете использовать в constness с const_cast, но это не прагматичное использование оператора. Цель новых стилей стиля (по сравнению с старым стилем c-стиля) заключается в том, чтобы сообщить о намерениях броска. const_cast - это запах кода, и его использование следует пересмотреть как минимум. static_cast, с другой стороны, безопасен. Но это вопрос стиля С++.

Или вы можете создать новый (закрытый) метод const и вызвать это из doOtherWork:

  void doSomeWorkOnProcess() const { getProcess().doSomeWork(); }

Использование временного константы также является опцией (ответ "MSN" ):

   const Bar* _this = this;
   _this->getProcess().doSomeWork();

Ответ 3

Если getProcess() и getProcess() const не возвращают ссылку на тот же объект (но по-разному), это указывает на плохой дизайн class Bar. Перегрузка по функции const не является хорошим способом отличить функции с разными формами поведения.

Если они возвращают ссылку на тот же объект, то:

const_cast<const Bar*>(this)->getProcess().doSomeWork();

и

getProcess().doSomeWork();

вызывать точно такую ​​же функцию doSomeWork(), поэтому нет необходимости использовать const_cast.

Ответ 4

Если бросок слишком уродлив для вас, вместо этого вы можете добавить метод Bar, который просто возвращает ссылку на константу *this:

Bar const& as_const() const {
    return *this;    // Compiler adds "const" without needing static_cast<>
}

Затем вы можете вызвать любой метод const в Bar только путем добавления as_const()., например:

as_const().getProcess().doSomeWork();

Ответ 5

Вам не нужно делать какие-либо каверзные обманки, если функция не перегружена. Вызов метода const неконстантного объекта в порядке. Он вызывает неконстантный метод из const-объекта, который запрещен. Если методы переопределены функцией const и non-const, то приведение объекта к const приведет к трюку:

const_cast<const IProcess&> (getProcess()).doSomeWork();

EDIT: Я не прочитал весь вопрос. Да, вам нужно const_cast этот указатель или сделать функцию doOtherWork const для вызова const IProcess & getProcess() const.

Точка остается, что вам не нужен объект const для вызова doSomeWork. Поскольку это цель, нужен ли вам метод const?

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

Ответ 6

определить шаблон

template< class T >
const T & addConst ( T & t ) 
{
    return t;
}

и вызовите

addConst( getProcess() ).doSomeWork();

Ответ 7

Хорошо, можете ли вы объявить

void doOtherWork const ()

?

Это сделало бы это.

Ответ 8

Я думаю, что метод const_cast - ваш лучший вариант. Это просто ограничение структуры const в С++. Я думаю, что единственный способ избежать кастинга - определить метод, который возвращает экземпляр const IProcess независимо. Например.

const IProcess* getProcessConst() const { return ... }
...
getProcessConst().doSomeWork();

Ответ 9

Я предполагаю, что вы хотите, чтобы 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     
  }
};

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

Ответ 10

Отправленный monjardin
Другой вариант - переименовать перегруженные функции. Это было бы действительно хорошей идеей, если бы у двух функций действительно было другое поведение/побочные эффекты. В противном случае эффект вызова функции не будет очевиден.

IProcess & доступен в другом коде в основном через свойство

__declspec(property(get=getProcess)) IProcess& Process;

поэтому переименование не было вариантом. Большинство констант времени вызывающей функции соответствуют getProcess(), поэтому проблем не было.

Ответ 11

Вы в основном застреваете с переименованием другого метода или const_cast.

Кстати, это одна из причин того, что интеллектуальные указатели копирования на запись на самом деле не работают на С++. Интеллектуальный указатель копирования на запись - это тот, который может быть разделен бесконечно. Когда пользователь обращается к данным в неконстантном контексте, создается копия данных (если пользователь не сохраняет уникальную ссылку). Этот вид указателя может быть очень удобным для использования при совместном использовании больших структур данных, которые должны модифицировать только некоторые клиенты. Наиболее "логическая" реализация состоит в том, чтобы иметь константу и неконстантный оператор- > . Версия const просто возвращает базовую ссылку. Неконстантная версия выполняет уникальную контрольную проверку и копирование. Он не может быть полезен, потому что неконтактный интеллектуальный указатель будет использовать неконстантный оператор- > по умолчанию, даже если вы хотите использовать версию const. Требование const_cast делает его очень недружественным пользователем.

Я приветствую всех, кто доказывает, что я ошибаюсь, и показывает удобный для пользователя указатель на запись на С++...