Вызов функции не-const-члена из функции-члена const

Я хотел бы знать, можно ли его вызвать функцию non-const member из функции const member. В приведенном ниже примере сначала дается ошибка компилятора. Я понимаю, почему это дает ошибку, я хотел бы знать, есть ли способ обойти это.

class Foo
{
   const int& First() const
   {
         return Second();
   }

   int& Second()
   {
        return m_bar;
   }

   int m_bar;
}

Я не хочу обсуждать мудрость этого, мне любопытно, возможно ли это даже возможно.

Ответ 1

return (const_cast<Foo*>(this))->Second();

Затем плачь, тихо.

Ответ 2

Возможно:

const int& First() const 
{ 
    return const_cast<Foo*>(this)->Second(); 
}

int& Second() { return m_bar; }

Я бы не рекомендовал это; это уродливое и опасное (любое использование const_cast является опасным).

Лучше всего перемещать как можно большую функциональность, чем вы можете, в вспомогательные функции, тогда ваши функции const и non-const будут выполняться так же мало, как вам нужно.

В случае простого аксессора, подобного этому, так же легко return m_bar; от обеих функций, как и для вызова одной функции от другой.

Ответ 3

По определению const, функция не должна изменять состояние объекта. Но если он вызывает другой неконстантный член, состояние объекта может быть изменено, поэтому оно запрещено.

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

Ответ 4

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

class CFoo
{ 
public:
    CFoo() {m_Foo = this;}
    void tee();

    void bar() const 
    { 
        m_Foo->m_val++;  // fine 
        m_Foo->tee();    // fine
    }
private:
   CFoo * m_Foo;
   int    m_Val;  

};

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

Ответ 5

Перегрузка на const:

const int& Second() const
{
    return m_bar;
}

Вы можете добавить этот метод и сохранить оригинальную неконстантную версию.

Ответ 6

итераторы схожи в этом и делают интересное исследование.

const-итераторы часто являются базой для итераторов 'non const', и вы часто найдете const_cast<>() или приведения стиля C, используемые для отбрасывания const из базового класса с помощью аксессуаров в дочернем элементе.

Изменить: Комментарий был

У меня есть zip-итератор, где const наследует от неконстантного

Это, как правило, неправильная структура наследования (если вы говорите, что я думаю, что вы есть), причина в том, что дети не должны быть менее ограничительными, чем родители.

скажем, что у вас был какой-то алгоритм, берущий ваш zip-итератор, было бы целесообразно передать константный итератор не const?

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

Вот краткое описание предполагаемой наследования после традиционной модели stl

class ConstIterator: 
    public std::_Bidit< myType, int, const myType *, const mType & >
{
  reference operator*() const { return m_p; }
}

class Iterator : public ConstIterator 
{
  typedef ConstIterator _Mybase;
  // overide the types provided by ConstIterator
  typedef myType * pointer;
  typedef myType & reference;

  reference operator*() const
  { 
    return ((reference)**(_Mybase *)this);
  }
}

typedef std::reverse_iterator<ConstIterator> ConstReverseIterator;
typedef std::reverse_iterator<Iterator> ReverseIterator;

Ответ 7

Я обнаружил, что пытаюсь вызвать не-const-функцию-член, которая была унаследована, но была фактически const из-за API, который я использовал. Наконец, я решил другое решение: переконвертировать API так, чтобы функция, которую я наследовала, была правильно const.

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