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

Posted

技术标签:

【中文标题】如何从 const 方法调用非 const 方法?【英文标题】:How to call a non-const method from a const method? 【发布时间】:2012-01-09 15:45:48 【问题描述】:

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

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

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

    // ....

    setColor(saveColor); // restore color

    return 1;

【问题讨论】:

这不是违反 const 函数的基本规则吗? @DumbCoder,从外部看,它是一个 const 函数,客户端可见的任何内容都没有改变。 mutable 关键字允许在 const 方法中更改数据,但没有人会建议停止使用 mutable 并将方法更改为非常量。作为一名程序员,我知道我正在设置一种颜色,然后恢复这种颜色。我知道数据没有改变,所以我正在寻找一种方法来向编译器表明这一点。 @Laurent:你说的是真的,但是如果有人创建了SomeClassconst 实例,那么修改其mutable 成员是定义行为,但UB 修改其非- 可变成员。因此,您实际拥有的情况与您与之比较的情况之间存在重要差异。标记someMethod const 的作用是允许调用者在const对象上调用它,以及通过references-to-const在非const对象上调用它,并且不能将两者分开。抛弃 const 依赖于调用者仅在非 const 对象上使用该函数。 一个可能的解决方案是更改// .... 中的代码,使其不需要使用对象的“当前颜色”。添加您使用的所有函数的版本,这些版本采用QColor 参数。当然,这依赖于能够更改隐藏代码中使用的接口。它也可能有不同的行为 - 在您的代码中,如果 // .... 抛出然后对象的颜色已更改,而在我的建议中您将失去这种效果。 【参考方案1】:

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

【讨论】:

我想可以使用工厂和私有构造函数来确保没有const 实例SomeClass。但是除非已经存在,否则对类接口的更改比提问者被禁止进行的更改要大得多,因此可能没有太大帮助。 这是一个比标记的更好的答案,因为它解释了何时可以获得未定义的行为。有时你别无选择,只能抛弃 const。【参考方案2】:

const-正确性的挑战之一是你不能半途而废。要么全有,要么全无。如果您尝试半途而废,那么您最终会陷入困境,就像您在这里一样。您最终会得到一个不错的 const-correct 类,该类被一些疯狂的旧代码使用,通常是旧的(或由旧的 curmudgeon 编写的)代码,这些代码不是 const-correct 并且它不起作用。你会想知道const-correctness 是否值得所有的麻烦。

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

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

显然你不能从const 方法调用非const 方法。否则,const 在应用于成员函数时将毫无意义。

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

您可以尝试通过执行 SomeClass* me = const_cast&lt;SomeClass*&gt;(this); 之类的操作来抛弃 constness,但 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();

【讨论】:

它有什么用处?我糊涂了。这里的代理不是代理,因为它不代表原始对象。它只是一个局部物体,没有非凡的力量。使用代理并不等同于使用原始对象。 @nawaz:如果它有助于 op 以符合标准的方式完成工作,那么它很有用。 有时编写一个类时没有 const 标记,因为 C++ 开发人员很懒惰,所以能够说“这个 really 是 const 即使它没有被标记为这样”是一回事有时。【参考方案3】:

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

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

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

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

【讨论】:

【参考方案4】:

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

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

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

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

 mutable QColor m_color;

然后将其设置在您的 const 函数中,无需调用 setColor 函数,也无需执行 const_cast

【讨论】:

这不是我刚刚写的问题的答案,我无法将其更改为非常量。 @Laurent,如果你能让成员接触到该功能mutable 如果这不是您问题的答案,那么您的问题是无法回答的。 @tenfour,然后投票关闭它。如果没有答案,那么跑题就没有意义了。 @Laurent:如果它被关闭,怎么知道这个问题有什么问题?关闭 please 是否比 尝试 回答你的答案更让你高兴?

以上是关于如何从 const 方法调用非 const 方法?的主要内容,如果未能解决你的问题,请参考以下文章

在 const 方法中调用非 const 方法[重复]

使用const_cast创建非const变量的方法

C++ 非 const 右值参数解决方法

const函数

const对象 不能调用非const修饰的成员函数

防止 const 类函数在引用成员上调用非 const 类函数