如何从const方法调用非const方法?

时间:2011-11-30 11:43:47

标签: c++ methods const const-correctness

我的类中有一个const方法,不能改为非const。在这个方法中,我需要调用一个非const方法,但编译器不允许我这样做。

周围有什么办法吗?以下是我的代码的简化示例:

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

    // ....

    setColor(saveColor); // restore color

    return 1;
}

4 个答案:

答案 0 :(得分:14)

您可以在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

答案 1 :(得分:8)

const的挑战之一 - 正确性是你不能半途而废。无论是全有还是全无。如果你试图半途而废,那你就像在这里一样陷入困境。你得到了一个很好的const - 正确的类被一些疯狂的旧的,通常是遗留的(或由旧的crummudgeon写的)代码使用,而不是const - 正确而且它不起作用。你不知道const是否正确无误。

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

你不能 - 不能直接。你也不应该。但是,还有另一种选择......

显然,您无法使用const方法调用非const方法。否则,const在应用于成员函数时没有任何意义。

const成员函数可以更改标记为mutable的成员变量,但您已指出在您的情况下这是不可能的。

您可以尝试通过执行类似const的操作来抛弃SomeClass* me = const_cast<SomeClass*>(this);但是A)这通常会导致UB,或者2)它违反了const的全部概念 - 正确性

你可以做的一件事,如果你真正想要实现的目标是支持这一点,那就是创建一个非const代理对象,并用它来做非const - y的东西。即:

#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();
}

答案 2 :(得分:7)

  

如何从const方法调用非const方法?

你不应该。如果使用this抛弃const_cast的常量,则可能会遇到未定义的行为。 const_cast的使用将关闭编译器,但这不是解决方案。如果您需要这样做,那么这意味着const函数首先不应该是const。使它成为非常数。

或者,您应该执行其他操作,这不需要您从const函数调用非const函数。比如,不要调用setColor函数?比如,将const函数拆分成多个函数(如果可以的话)?或者是其他东西?

在您的特定情况下,如果setColor仅设置某个成员变量,例如m_color,那么您可以声明mutable

 mutable QColor m_color;

然后在const函数中设置它,而不调用setColor函数,而不执行const_cast

答案 3 :(得分:7)

如果您需要更改const - 方法中的某些内部状态,您还可以声明受影响的状态mutable

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

这适用于您将类似互斥锁的内容作为班级成员的情况。获取和释放互斥锁不会影响客户端可见状态,但在const - 方法中技术上是禁止的。解决方案是标记互斥锁mutable。您的案例看起来很相似,但我认为您的课程需要进行一些重构才能使此解决方案适用。

此外,您可能希望阅读this answer以了解如何使用RAII使此临时状态更改异常安全。