const_cast 为函数 const 设置规则并打破它

const_cast setting a rule and breaking it for function const

在我在网上找到的以下示例中,提到const_cast 的优点之一是它允许常量函数更改class 成员。这对我来说是个问题。为什么我们应该通过 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;
}

reference

const主要是向来电者表达意图。当一个成员函数被标记为 const 时,您是在告诉 调用者 他们可以期待此函数的 public 接口 对象不改变。

但想象一下您想要使用序列号记录对该函数的调用的场景。该序列号需要更改,但此更改仅在 class 的私人深处可见。在这种情况下 "cheat" const my 将序列号变量标记为 mutable.

是合适的

const_cast也是类似的道理。

这确实是个坏主意。除了对函数的行为撒谎外,它还允许您修改常量 student 对象的成员,从而给出未定义的行为。

一般来说,当且仅当它不修改对象的可观察状态时,成员函数才应该是 const。所以在这种情况下,它不应该是 const.

有时,您可能希望特定成员在函数中可以修改,否则不会导致可观察到的变化;例如,锁定互斥量以访问共享数据,或缓存复杂计算的结果。在那种情况下,声明那些成员 mutable,以便 class 的其余部分仍然受到 const-正确性的保护。

这是 const_cast 用法的糟糕示例。想象一个更好的例子。已发布的 class 的方法未被错误地声明为 const。您有一个对此 class 的常量引用并希望调用此方法。但是你不能这样做,因为它没有被错误地声明为const 。在这种情况下,您可以对编译器说:"Ok, I know what I'm doing, I know this method does not actually change anything, just remove const-ness from that reference and allow me to call this method. Trust me, I'm a programmer".

现实生活中的例子。在 OpenCV 库中,没有不可变图像这样的东西。核心 class cv::Mat 是可变的。假设您想围绕一个常量内存缓冲区创建一个只读包装器。构造它的唯一方法是强制转换 const,如下所示:

const char* myConstBuffer = GetConstBuffer();
const cv::Mat myConstImage(const_cast<char*>(myConstBuffer), /* dimensions, etc. */);

这是一个合法的代码,因为构造图像的类型是const cv::Mat,你不能在它上面调用任何修改方法。但是这里使用const_cast仍然暴露了一个设计错误:应该有一个有效的方法来构造这样的只读缓冲区。

最好的例子——引用计数对象。事实上,引用计数声明了对象生命周期策略,但与 class 实现的真实 "business" 流程无关。而 const 与业务流程有关。例如 - 您有企业帐户,但无法更改它:

class BusinessAccount{
   unsigned _refcount;
   double _amount
   ...

你有一些操作要"view"

void view(SmartPtr<BusinessAccount> smart_ptr)

因此,如果 view 必须取得对象的所有权 - 它必须增加 _refcount。

PS 关键字的更好解决方案 - mutable 在字段 _refcount 而不是 const_cast