如何从 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:你说的是真的,但是如果有人创建了SomeClass
的const
实例,那么修改其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<SomeClass*>(this);
之类的操作来抛弃 const
ness,但 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 方法?的主要内容,如果未能解决你的问题,请参考以下文章