const_cast为函数const设置规则并破坏规则

const_cast setting a rule and breaking it for function const

本文关键字:规则 const 函数 cast 设置      更新时间:2023-10-16

在下面我在网上找到的例子中,提到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