2011-11-30 83 views
8

我在我的类中有一个const方法,它不能更改为非const。在这种方法中,我需要调用非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; 
} 
+3

这不是违背常量函数的基本规则吗? – DumbCoder

+2

@DumbCoder,从外部看,它是一个const函数,因为客户端没有任何可见的变化。 –

+0

非const方法意味着它正在改变对象中的一些数据。如果'someMethod()'调用非const方法,那么它会间接地改变数据。所以真的,'someMethod()'不应该是'const'。 –

回答

5

const-正确性的挑战之一是你不能半途而废。它可以是全部或全部。如果你试图做到这一点,你最终会遇到一个像你这样的难题。你最终会得到一个不错的const-正确的类正在被一些疯狂的旧的,通常遗留的(或由旧的crummudgeon编写的)代码使用,它不是const-正确的,它只是不起作用。你仍然想知道const-正确性是否值得所有的麻烦。

​​

你不能 - 不能直接。你也不应该。但是,还有一种替代方法...

显然,您不能通过const方法调用非const方法。否则,const应用于成员函数时将没有意义。

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

你可以尝试做一些像SomeClass* me = const_cast<SomeClass*>(this);抛掷const内斯,但A)这通常会导致UB,或2)违反const -correctness的整体思路。

你可以做的一件事情是,如果你真的想要完成的事情能够支持这个,那就是创建一个非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(); 
} 
+0

它有什么用?我很困惑。此处的代理不是代理,因为它不代表原始对象。它只是一个没有超凡力量的本地物体。使用代理不等同于使用原始对象。 – Nawaz

+2

@nawaz:如果它能帮助我们以标准一致的方式完成他的工作,那么它很有用。 –

11

你可以在this指针使用const_cast

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

我想可以使用工厂和私有构造函数,以确保没有'SomeClass'的'const'实例。但除非已经存在,否则对于类接口来说,这是一个比提问者禁止更改更大的改变,所以可能没有多大帮助。 –

5

如何从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

+0

这不是我刚才写的问题的答案,我不能将其更改为非const。 –

+0

@Laurent:查看编辑。 – Nawaz

+2

@Laurent,如果你可以让这个成员碰到这个函数'mutable',你有可能吗? – Nim

6

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

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

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

此外,您可能想要阅读this answer,以了解如何使用RAII使这种暂时的状态更改异常安全。