19

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

有什么办法吗?这是我的代码的简化示例:

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

    // ....

    setColor(saveColor); // restore color

    return 1;
}
4

4 回答 4

21

你可以使用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放在首位。

于 2011-11-30T11:47:11.170 回答
11

做正确的挑战之一const是你不能半途而废。要么全有,要么全无。如果您尝试半途而废,那么您最终会陷入困境,就像您在这里一样。您最终会得到一个不错的const-correct 类,该类被一些疯狂的旧的、通常是遗留的(或由旧的 curmudgeon 编写的)代码使用,这些代码不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();
}
于 2011-11-30T18:17:55.103 回答
10

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

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

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

此外,您可能想阅读此答案以了解如何使用 RAII 使此临时状态更改异常安全。

于 2011-11-30T11:54:13.033 回答
6

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

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

或者,您应该做其他事情,这不需要您从函数中调用非常量const函数。比如,不要调用setColor函数?比如,将 const 函数拆分为多个函数(如果可以的话)?或者是其他东西?

在您的特定情况下,如果setColor只设置一些成员变量,例如m_color,那么您可以声明它mutable

 mutable QColor m_color;

然后将其设置在您的 const 函数中,不调用setColor函数,也不做const_cast.

于 2011-11-30T11:48:00.160 回答