【问题标题】:const_cast setting a rule and breaking it for function constconst_cast 设置规则并为函数 const 打破它
【发布时间】:2015-04-09 07:08:02
【问题描述】:

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

【问题讨论】:

  • 有趣的是getter不是const
  • C++ 提供了很多方法让自己在脚上开枪,这就是其中之一。
  • 我认为 const_cast 的主要理由之一是能够调用未正确将其参数声明为 const 的旧 C API 函数(通常是指向 const 的指针)。这将使这些 API 无法从 const 方法调用(对 const 成员进行操作)。但是您可能知道该函数不会更改其参数(例如 strcmp)。 const_cast 可以让你去掉 const 以便能够使用该函数。

标签: c++ c++11 const-cast


【解决方案1】:

这是const_cast 用法的一个糟糕示例。想象一个更好的例子。已发布类的方法未错误地声明为const。你有一个对这个类的 const-reference 并且想要调用这个方法。但是你不能这样做,因为它没有被声明为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 仍然暴露了一个设计错误:应该有一个有效的方法来构造这样的只读缓冲区。

【讨论】:

    【解决方案2】:

    亮例——引用计数对象。事实上,引用计数声明了对象生命周期策略,但与类实现的真正“业务”流程无关。而const 与业务流相关。例如 - 您有企业帐户,但无法更改:

    class BusinessAccount{
       unsigned _refcount;
       double _amount
       ...
    

    你有一些操作要“查看”

    void view(SmartPtr<BusinessAccount> smart_ptr)
    

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

        【解决方案4】:

        const 主要是向来电者表达意图。当成员函数标记为const 时,您是在告诉调用者他们可以期望该对象的公共接口不会改变。

        但是想象一个场景,您希望使用序列号记录对该函数的调用。该序列号将需要更改,但此更改仅在类的私有深度内可见。在这种情况下,“欺骗”const my 将序列号变量标记为mutable 是合适的。

        const_cast 是类似的原理。

        【讨论】:

        • 我认为const_cast 在这种情况下不合适。听起来像是mutable 的完美案例。
        猜你喜欢
        • 2018-11-15
        • 2013-04-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-24
        • 2015-02-15
        • 1970-01-01
        相关资源
        最近更新 更多