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

4
在我在网上找到的以下示例中,提到了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;
}

reference


5
有趣的是getter不是“const”。 - Jarod42
C ++ 提供了许多让你自己中枪的方式,这是其中之一。 - Anton Savin
1
我认为 const_cast 的主要理由之一是可以调用旧的 C API 函数,这些函数没有正确声明其参数为 const(通常是指向 const 的指针)。这将使得这些 API 无法从 const 方法(对 const 成员进行操作)中调用。但是你可能知道该函数不会更改其参数(比如 strcmp)。const_cast 可以让你去除 const 以便能够使用该函数。 - Andre Kostur
4个回答

5
那确实是个坏主意。除了谎称函数的行为外,它还允许您修改常量student对象的成员,导致未定义的行为。
一般来说,只有当成员函数不修改对象的可观察状态时,它才应该是const。所以在这种情况下,它不应该是const
有时候,您可能希望在一个不会否则引起可观察变化的函数中修改特定的成员;例如,锁定互斥体以访问共享数据,或者缓存复杂计算的结果。在这种情况下,声明那些成员为mutable,以便类的其余部分仍受到const正确性的保护。

2
这是一个糟糕的const_cast使用示例。想象一个更好的例子。一个已发布类的方法由于错误而未声明为const。您有一个对该类的const引用,并且想要调用此方法。但是你不能这样做,因为它没有被const声明为错误。在这种情况下,您可以告诉编译器:“好的,我知道自己在做什么,我知道这个方法实际上并不改变任何东西,只需从引用中删除const-ness并允许我调用此方法。相信我,我是一名程序员。”
现实生活中的例子。在OpenCV库中,不存在不可变图像。核心类cv :: Mat 是可变的。假设您想在常量内存缓冲区周围创建一个只读包装器。您唯一能构建它的方式是通过去除const,像这样:
const char* myConstBuffer = GetConstBuffer();
const cv::Mat myConstImage(const_cast<char*>(myConstBuffer), /* dimensions, etc. */);

这是一个法律代码,因为构造的图像具有类型const cv :: Mat ,您不能调用任何修改方法。但是,在此处使用const_cast 仍然会显示设计错误:应该有一种有效的方法来构造这样的只读缓冲区。


0

一个明显的例子是引用计数对象。实际上,引用计数声明了对象的生命周期策略,但与类实现的实际“业务”流程无关。而const则与业务流程相关。例如 - 你有一个业务账户,但没有能力更改它:

class BusinessAccount{
   unsigned _refcount;
   double _amount
   ...

你有一些“查看”操作。
void view(SmartPtr<BusinessAccount> smart_ptr)

因此,如果view必须对对象进行所有权控制,则必须增加_refcount。

PS更好的解决方案是在字段_refcount上使用关键字mutable,而不是使用const_cast


0

const 主要是用于向调用者表达意图。当一个成员函数被标记为 const 时,你告诉调用者他们可以期望这个对象的 公共接口 不会改变。

但是想象一种情况,你想记录对这个函数的调用,带有一个序列号。这个序列号需要改变,但是这个改变只在类的私有深度内可见。在这种情况下,通过将序列号变量标记为 mutable 来“欺骗” const 是合适的。

const_cast 的理由类似。


2
我认为在这种情况下使用const_cast并不合适。听起来mutable是完美的选择。 - Mikhail

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接