const_cast为函数const设置规则并破坏规则
const_cast setting a rule and breaking it for function const
在下面我在网上找到的例子中,提到const_cast
的优点之一是它允许一个常量函数更改类成员。这对我来说是个问题。为什么我们要用const
为函数设置一个规则,然后用const_cast
打破这个规则?这不是作弊吗?根本不为函数设置const
不是更好吗?
#include <iostream>
using namespace std;
class student
{
private:
int roll;
public:
student(int r):roll(r) {}
// A const function that changes roll with the help of const_cast
void fun() const
{
( const_cast <student*> (this) )->roll = 5;
}
int getRoll() { return roll; }
};
int main(void)
{
student s(3);
cout << "Old roll number: " << s.getRoll() << endl;
s.fun();
cout << "New roll number: " << s.getRoll() << endl;
return 0;
}
参考
这确实是个坏主意。除了谎报函数的行为外,它还允许您修改常量student
对象的成员,从而给出未定义的行为。
通常,成员函数应该是const
,如果并且仅当它不修改对象的可观察状态。所以在这种情况下,它不应该是const
。
有时,您可能希望特定成员在函数中是可修改的,否则不会导致可观察到的更改;例如,锁定互斥对象以访问共享数据,或者缓存复杂计算的结果。在这种情况下,声明那些成员mutable
,这样类的其余部分仍然受到const
-正确性的保护。
这是const_cast
用法的一个糟糕示例。想象一个更好的例子。已发布类的方法没有错误地声明为const
。您有一个对此类的const引用,并且希望调用此方法。但是您不能这样做,因为它没有被错误地声明为const
。在这种情况下,你可以对编译器说:"好吧,我知道我在做什么,我知道这个方法实际上不会改变任何东西,只是从引用中删除constness,并允许我调用这个方法。相信我,我是一个程序员"。
现实生活中的例子。在OpenCV库中,不存在不可变的图像。核心类cv::Mat
是可变的。假设您想创建一个只读包装器,围绕一个恒定的内存缓冲区。构造它的唯一方法是抛出const,如下所示:
const char* myConstBuffer = GetConstBuffer();
const cv::Mat myConstImage(const_cast<char*>(myConstBuffer), /* dimensions, etc. */);
这是一个合法的代码,因为构造的映像的类型为const cv::Mat
,您不能对其调用任何修改方法。但在这里使用const_cast
仍然会暴露出一个设计错误:应该有一种有效的方法来构造这种只读缓冲区。
const
主要是向呼叫者表达意图。当一个成员函数被标记为const
时,您将告诉调用方他们可以期望该对象的公共接口不会更改。
但是想象一个场景,您想要用序列号记录对该函数的调用。该序列号需要更改,但此更改仅在类的私有深度内可见。在这种情况下,通过将序列号变量标记为mutable
来"欺骗"const是合适的。
const_cast
也是类似的原理。
明亮的例子-引用计数对象。事实上,引用计数声明了对象生命周期策略,但和类实现的实际"业务"流无关。而const
与业务流有关。例如,你有商业账户,但没有能力更改它:
class BusinessAccount{
unsigned _refcount;
double _amount
...
你有一些操作来"查看"
void view(SmartPtr<BusinessAccount> smart_ptr)
所以,若view
必须获得对象的所有权,它必须增加_refcount。
PS更好的解决方案是关键字-字段_refcount上的mutable
,而不是const_cast