首页 > 编程语言 >正确使用C++的const_cast

正确使用C++的const_cast

时间:2023-06-14 22:34:09浏览次数:68  
标签:const int C++ cast 引用 type

C++的四种类型转换之const_cast

前言

引用《Effective C++ 中文版第三版》中条款27 "尽量少做转型动作"中的一段话:

C++规则的设计目标之一是,保证“类型错误”绝对不可能发生,理论上如果你的程序很“干净”的通过编译,就表示它并不企图在任何对象上执行任何不安全、无意义、愚蠢荒谬的操作。这是一个极具价值的保证,可别草率的放弃它。
不幸的是,转型(cast)破坏了类型系统(type system),那可能导致任何种类的麻烦,有些容易辨识,有些非常隐晦。

现实情况是类型转换在开发中无法避免,在开始探讨C++的类型转换以前我们先看下C风格的类型转换。

(T)varibale
T(variable)

这种旧式类型转换目前依旧经常被用到,但是新式类型转换却更应该被我们去使用,这是因为:

  • 1.容易被辨识,从而更容易在程序出问题时找到问题所在
  • 2.职责划分更明细,编译器更可能在编译期找到问题。
  • 3.有更强的类型转换能力。

目前C++提供的四种新式类型转换为

const_cast<T>()
dynamic_cast<T>()
reinterpret_cast<T>()
static_cast<T>()

下面我们就const_cast,分别研究下其用途以及适用的使用场景

const_cast

const_cast<new type>(express)的主要用途是,移除对象的常量性,并且也是唯一具有此能力的C++风格的转型操作符

在C++11中,const_cast可以完成以下类型转换

  • 两个可能指向同一类型的多级指针可以相互转换,而不考虑每一层上的cv性质(const and volatile)。
  • 空指针值可以转换为新类型的空指针值.

可以看出,const_cast主要针对指针进行操作,其能力可以大概被总结为:

1、常量指针被转化成非常量的指针,并且仍然指向原来的对象; 2、常量引用被转换成非常量的引用,并且仍然指向原来的对象;

const_cast的返回结果根据需要转换出的新类型,可以区别为:

  • 如果new type是lvalue引用,或者是函数类型的rvalue引用,则返回lvalue。
  • 如果new type是对象类型的rvalue引用,则返回xvalue。
  • 否则返回prvalue。

以下时关于几个value的解释:

  • lvalue (Left-hand-side value)
  • rvalue (Right-hand-side value)
  • xvalue (eXpiring value)
  • prvalue (Pure rvalue)
  • glvalue (Generalized lvalue)

For all the values, there were only two independent properties:

  • "has identity" – i.e. an address, a pointer, the user can determine whether two copies are identical, etc.use "i" represent
  • "can be moved from" – i.e. we are allowed to leave to source of a "copy" in some indeterminate, but valid state.use "m" represent.

There are four possible composition:

  • iM: has identity and cannot be moved from (defined as lvalue)
  • im: has identity and can be moved from (defined as xvalue)
  • Im: does not have identity and can be moved from (defined as prvalue)
  • IM: doesn't have identity and cannot be moved (他认为这种情况在 C++ 中是没有用的)

以上出自于https://cloud.tencent.com/developer/article/1493839

需要注意的是,const_cast中:

  1. 指向函数的指针和指向成员函数的指针不受const_cast约束。
  2. const_cast可以形成一个指向非const类型的引用或指针,它实际上引用了一个const对象,也可以形成一个指向非volatile类型的引用或指针,它实际上引用了一个volatile对象。
  3. 通过非const访问路径修改const对象并通过非volatile glvalue引用volatile对象会导致未定义的行为。

未定义行为:C++标准对此类行为没有做出明确规定.同一份代码在使用不同的编译器会有不同的效果

**《C++ Primer》《Effective C++》是C++开发者必不可少的书籍,如果你想入门C++,以及想要精进C++开发技术,这两本书可以说必须要有。此外,《Linux高性能服务器编程》以及《Linux多线程服务端编程:使用muduo C++网络库》.(陈硕)》是快速提高你的linux开发能力的秘籍。在网上搜索相关资源也要花费一些力气,需要的同学可以关注公众号【程序员DeRozan】,回复【1207】**快速免费领取~

下面通过例子来分析const_cast的用法,C++版本为C++11

1.new type为左值引用

将一个常量左值引用转换为一个非常量左值引用:

 int i = 3; // i is not declared const
    const int &rci = i;
    const_cast<int &>(rci) = 4; // OK: modifies i
    std::cout << "i = " << i << '\n';

控制台输出

sh-4.4$ ./build/linux/x86_64/release/Class-convert 
i = 4

即,如果new type为左值引用,则返回值是一个左值

2. new type为函数类型的右值引用

如果new type的类型为函数右值引用,则const_cast的返回值为左值

void printHello(){
    cout<<"hello world"<<endl;
}

void printHello2(){
    cout<<"hello world 2"<<endl;
}

int main(){
    
    const std::reference_wrapper<void()>x = std::ref(printHello);
    // x = printHello2; //编译错误,const类型的函数右值引用
    const_cast<std::reference_wrapper<void()> &&>(x) = printHello2;  
    x();
}

3.new type为对象类型的右值引用

将一个常量对象右值引用,转换为一个非常量的对象类型引用:

class OBJ {
    public:
    int num;
    OBJ(int i){num = i;}
    ~OBJ(){}
};


int main()
{

    const OBJ&& obj = OBJ(1);
    cout<<"obj.num="<<obj.num<<endl;

    // obj.num = 3;  //编译错误,这里是const引用

    // const_cast<OBJ&&>(obj).num = 4;// 编译错误,error: using xvalue (rvalue reference) as lvalue
    // cout << "obj.num=" << obj.num<<endl;
    
    OBJ &&obj2 = const_cast<OBJ &&>(obj);  //编译通过
    obj2.num = 3;
    cout << "obj.num=" << obj.num << endl;
}

4.指向函数的指针和指向成员函数的指针不受约束

struct type
{
    int i;

    type() : i(3) {}

    void f(int v) const
    {
        // this->i = v;                 // compile error: this is a pointer to const
        const_cast<type *>(this)->i = v; // OK as long as the type object isn't const
    }
};
int main(){
      [[maybe_unused]] void (type::*pmf)(int) const = &type::f; // pointer to member function
    // const_cast<void(type::*)(int)>(pmf);   // compile error: const_cast does
    // not work on function pointers   
}

5.通过非const访问路径修改const对象导致未定义行为

    const int j = 3; // j is declared const
    [[maybe_unused]] int *pj = const_cast<int *>(&j);
    // *pj = 4;      // undefined behavior

6.const_cast只能用来修改指针,引用

   const int j = 3; // j is declared const
   int ppj = const_cast<int>(j); // 编译错误,invalid use of const_cast with type ‘int’, which is not a pointer, reference, nor a pointer-to-data-member type
 

 from:https://zhuanlan.zhihu.com/p/611350793

 

标签:const,int,C++,cast,引用,type
From: https://www.cnblogs.com/im18620660608/p/17481536.html

相关文章

  • C++面试八股文:C++中,设计一个类要注意哪些东西?
    某日二师兄参加XXX科技公司的C++工程师开发岗位第9面:面试官:C++中,设计一个类要注意哪些东西?二师兄:设计一个类主要考虑以下几个方面:1.面向对象的封装、继承及多态。2.bigthree或者bigfive。3.运算符和函数重载、静态成员、友元、异常处理等相关问题。面试官:请介绍一下面向......
  • 《C++》对象的初始化和清理
    不设计构造和析构函数 编译器会提供空语句的构造和析构初始化--构造函数无返回类型函数名与类名相同构造函数可以有参数可以发生重载创建对象的时候构造函数会自动调用且只调用一次classPerson{public: Person() { cout<<"无参构造函数调用"<<endl; }Person(inta......
  • C++ const_cast用法
    原文C++const_cast用法const_cast是一种C++运算符,主要是用来去除复合类型中const和volatile属性(没有真正去除)。变量本身的const属性是不能去除的,要想修改变量的值,一般是去除指针(或引用)的const属性,再进行间接修改。用法:const_cast<type>(expression)通过const_cast运算符,也只......
  • [C++/PTA] 有序数组(类模板)
    题目要求实现一个类模板,它可以接受一组数据,能对数据排序,也能输出数组的内容。每行输入的第一个数字为0,1,2或3:为0时表示输入结束;为1时表示将输入整数,为2时表示将输入有一位小数的浮点数,为3时表示输入字符。如果第一个数字非0,则接下来将输入一个正整数,表示即将输入的数据的数量......
  • [C++/PTA] 2017Final 圆周率山
    题目要求为了参加学校的社团风采展,怡山小学数学组的同学们决定画一座圆周率山,以宣传圆周率。已知圆周率为:3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253......
  • [C++/PTA] 类的定义和使用
    题目要求定义一个日期类Date,内有数据成员年、月、日,另有成员函数:构造函数用于初始化数据成员,输出,闰年的判断。编写主函数:创建日期对象,计算并输出该日是该年的第几天。输入:每组测试数据仅包含一个测试用例,每个测试用例占一行包括三个数,分别表示年、月、日。输出:该日是该年的......
  • [C++/PTA] 立方体类的实现
    题目要求立方体类Box的实现,完成计算体积、计算表面积、输出结果等功能。其中给定的主函数为:intmain(){floatab;cin>>ab;Boxobj;obj.seta(ab);obj.getvolume();obj.getarea();obj.disp();return0;}输入格式:立方体的边......
  • [C++/PTA] 汽车收费
    题目要求现在要开发一个系统,管理对多种汽车的收费工作。给出下面的一个基类框架classVehicle{protected:stringNO;//编号public:virtualvoiddisplay()=0;//输出应收费用}以Vehicle为基类,构建出Car、Truck和Bus三个类。Car的收费公式为:载客数8+重量2Truck的收费......
  • [C++/PTA] 计算时间相减
    题目要求题目描述:定义一个时间类,小时和分钟是其两个私有成员数据。输入一个起始时间和一个结束时间(起始时间早于结束时间),通过运算符重载-(减号),计算这两个时间相隔多少分钟。说明:这两个时间在同一天之内,且采用24小时计时分式,即从00:00-23:59。输入格式:测试输入包含若干测......
  • [C++/PTA] 括号匹配
    题目要求给定仅包含()[]{}六种括号的字符串,请你判断该字符串中,括号的匹配是否是合法的,也就是对应括号的数量、嵌套顺序完全正确。输入格式:第一行一个整数T(T<=10)其后T行每行一个字符串只包含[{()}]六种字符(字符串长度2e5以内)输出格式:对于每个字符串,匹配输出Yes,否则输出No......