Как вызвать неконстантный метод из константного метода? - PullRequest
13 голосов
/ 30 ноября 2011

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

Есть ли способ обойти это?Вот упрощенный пример моего кода:

int SomeClass::someMethod() const {
    QColor saveColor = color();
    setColor(QColor(255,255,255)); // Calling non-const method

    // ....

    setColor(saveColor); // restore color

    return 1;
}

Ответы [ 4 ]

14 голосов
/ 30 ноября 2011

Вы можете использовать const_cast для указателя this,

int SomeClass::someMethod() const {
    const_cast<SomeClass*>( this )->setColor(...);// Calling non-const method
    //whatever
}

, но если вы сделаете это для объекта, который был первоначально объявлен const, вы столкнетесь с неопределенным поведением.

Итак, это:

SomeClass object;
object.someMethod();

нормально, но это:

const SomeClass object;
object.someMethod();

дает неопределенное поведение.

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

8 голосов
/ 30 ноября 2011

Одна из проблем правильности const в том, что вы не можете сделать это наполовину. Это либо все, либо ничего. Если вы попытаетесь сделать это на полпути, вы окажетесь в трудном положении, как вы здесь. В результате получается хороший const -корректный класс, который используется каким-то сумасшедшим старым, обычно устаревшим (или написанным старым хламом) кодом, который не является const -корректным и просто не работает. Вы задаетесь вопросом, стоит ли const -корректность всех трудностей.

I need to call a non-const method [from a const method]

Вы не можете - не напрямую. Как и вы. Однако есть альтернатива ...

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

Функция-член const может изменять переменные-члены, помеченные mutable, но вы указали, что в вашем случае это невозможно.

Вы можете попытаться отбросить const ness, выполнив что-то вроде SomeClass* me = const_cast<SomeClass*>(this);, но A) Это обычно приводит к UB, или 2) Это нарушает саму идею const -корректности.

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

#include <iostream>
#include <string>
using namespace std;

class Gizmo
{
public:
    Gizmo() : n_(42) {};
    void Foo() const;
    void Bar() { cout << "Bar() : " << n_ << "\n"; }
    void SetN(int n) { n_ = n; };
    int GetN() const { return n_; }
private:
    int n_;
};

void Gizmo::Foo() const
{
    // we want to do non-const'y things, so create a proxy...
    Gizmo proxy(*this);
    int save_n = proxy.GetN();
    proxy.SetN(save_n + 1);
    proxy.Bar();
    proxy.SetN(save_n);
}

int main()
{
    Gizmo gizmo;
    gizmo.Foo();
}
7 голосов
/ 30 ноября 2011

Если вам требуется изменить некоторое внутреннее состояние внутри const -метода, вы также можете объявить уязвимое состояние mutable:

class Foo {
public:
    void doStuff() const { bar = 5; }
private:
    mutable int bar;
};

Это предназначено для случаев, когда в вашем классе есть такие вещи, как мьютексы. Получение и освобождение мьютекса не влияет на состояние, видимое клиенту, но технически запрещено методом const. Решение состоит в том, чтобы пометить мьютекс mutable. Ваш случай выглядит аналогично, хотя я думаю, что вашему классу требуется некоторый рефакторинг, чтобы это решение было применимо.

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

7 голосов
/ 30 ноября 2011

Как вызвать неконстантный метод из метода const?

Не следует.Вы можете столкнуться с неопределенным поведением, если отбросите константу this, используя const_cast.Использование const_cast закроет рот компилятору, но это не решение.Если вам нужно это сделать, то это означает, что функция const не должна быть const в первую очередь.Сделайте его неконстантным.

Или, вы должны сделать что-то еще, что не потребует от вас вызова неконстантной функции из const функции.Мол, не вызывать функцию setColor?Мол, разделить функцию const на несколько функций (если вы можете это сделать)?Или что-то другое?

В вашем конкретном случае, если setColor устанавливает только некоторую переменную-член, скажем, m_color, вы можете объявить ее mutable:

 mutable QColor m_color;

и затем установить ее в своемконстантная функция, без вызова setColor функции и без выполнения const_cast.

...