-
2022-06-18 08:39:16
C++ 强制类型转换:static_cast、dynamic_cast、const_cast 和 reinterpret_cast
static_cast
static_cast<type-id>(expression)
将
expression
转换为type-id
类型。static_cast
是静态类型转换,发生在编译期。这种转换不会进行运行时的动态检查(RTTI),因而这种转换可能是不安全的。static_cast
典型应用场景如下:1. 类的层级结构中,基类和子类之间指针或者引用的转换。
上行转换(Upcasting),也即子类像基类方向转换,是安全的。
下行转换(Downcasting),也即基类向子类方向转换,是不安全的,需要程序员自行保证安全转换。下面举例说明:
class A { public: virtual void func() { std::cout << "A::func()" << std::endl; } }; class B : public A { public: virtual void func() { std::cout << "B::func()" << std::endl; } void print() { std::cout << "B::print()" << std::endl; } };
对于上行转换,肯定是安全的。
B* pb = new B(); A* pa = static_cast<A*>(pa); pa->func();
对于下行转换:
A* pa = new B(); B* pb = static_cast<B*>(pa); pb->print();
这里,
A* pa = new B();
,由于 C++ 的多态的支持,可以使用基类指针指向子类。这里的转换是安全的,因为pa
初始化就指向的就是B
。而下面的转换则是不安全的:A* pa = new A(); B* pb = static_cast<B*>(pa); pb->print();
此外,对于两个不存在继承关系的两个类之间转换,总是失败的,编译器报错:
#include <iostream> class A { virtual void func(){} }; class B { virtual void func(){} }; int main(){ A* pa = new A(); B* pb = static_cast<B*>(pa); return 0; }
2. 基本数据类型间的转换。这种转换也是不安全的,需要程序员自行保证安全转换。 例如
int
转short
,直接高位截断;而short
转int
则高位根据符号位填充。两种不同类型指针间相互转换是相当危险的,例如int*
转float*
。将 int 转换为指针类型也是危险的转换,例如float* p = static_cast<float*>(0X2edf);
3. 将
void
类型转换为其他类型的指针。 显然这种转换也是不安全的,需要程序员自行保证安全转换。4. 把其他类型转换为
void
类型。- 有转换构造函数或者类型转换函数的类与其它类型之间的转换。例如:
#include <iostream> class Point{ public: Point(double x, double y): m_x(x), m_y(y){ } Point(double& x): m_x(x), m_y(1.1){ } public: operator double() const { return m_x; } //类型转换函数 void print() { std::cout << "m_x: " << m_x << " m_y: " << m_y << std::endl; } private: double m_x; double m_y; }; int main() { Point p1(12.5, 23.8); double x= static_cast<double>(p1); // std::cout << x << std::endl; Point p2 = static_cast<Point>(x); // p2.print(); return 0; }
dynamic_cast
dynamic_cast<type-id>(expression)
把
expression
转换为type-id
类型,type-id
必须是类的指针、类的引用或者是void *
;如果type-id
是指针类型,那么expression
也必须是一个指针;如果type-id
是一个引用,那么expression
也必须是一个引用。dynamic_cast
提供了运行时的检查。对于指针类型,在运行时会检查expression
是否真正的指向一个type-id
类型的对象,如果是,则能进行正确的转换;否则返回nullptr
。对于引用类型,若是无效转换,则在运行时会抛出异常std::bad_cast
。T1 obj; T2* pObj = dynamic_cast<T2*>(&obj); // 无效转换返回 nullptr T2& refObj = dynamic_cast<T2&>(obj); // 无效转换抛出 bad_cast 异常
上行转换:其实和 static_cast 是一样的,一般肯定能成功。例如前面用到的例子:
// A->B B* pb = new B(); A* pa = static_cast<A*>(pa);
但是,下面这种继承关系会转换失败:
#include <iostream> /* A / \ V V B C \/ v D */ class A { virtual void func(){} }; class B : public A { void func(){} }; class C : public A { void func(){} }; class D : public B, public C { void func(){} }; int main(){ D* pd = new D(); A* pa = dynamic_cast<A*>(pd); return 0; }
上面这个例子,虽然也是上行转换,但是存在两条路径,在 B 和 C 都继承于 A,并且有虚函数实现,上行转换不知道从哪条路径进行转换。下面的写法则没问题:
D* pd = new D(); B* pb = dynamic_cast<B*>(pd); A* pa = dynamic_cast<A*>(pb);
下行转换:看个例子。
#include <iostream> class A { virtual void func(){} }; class B : public A { void func(){} }; int main(){ A* pa1 = new B(); A* pa2 = new A(); B *pb1 = dynamic_cast<B*>(pa1); // ok B *pb2 = dynamic_cast<B*>(pa2); // pb2 is a nullptr! return 0; }
其实
dynamic_cast
本质只支持上行转换,只会沿着继承链向上遍历,找到目标类型则转换成功,否则失败。dynamic_cast
看似支持下行转换,这都是多态的缘故。上面的例子,pa1
虽然类型是A
,但实际指向B
,沿着B
向上可以找到B
,因为第一个转换可以成功。而pa2
指向A
,沿着A
向上找不到B
类型,因而转换失败。因而在有继承关系的类的转换时候,
static_cast
转换总是成功的,dynamic_cast
显然比static_cast
更加安全。const_cast
const_cast
用来去掉表达式的const
修饰或volatile
修饰,也就是将const
或volatile
类型转换为非const
或 非volatile
类型。#include <iostream> int main(){ const int n = 111; int *p = const_cast<int*>(&n); *p = 222; std::cout<< "n = " << n << std::endl; std::cout<< "*p = " << *p << std::endl; return 0; }
这里需要注意:按照正常理解,n 的打印值应该是 222。但是,由于编译器的常量传播优化,
std::cout<< "n = " << n << std::endl;
会被编译器替换成类似std::cout<< "n = " << 111 << std::endl;
的语义。reinterpret_cast
reinterpret_cast
转换直接对二进制位按照目标类型重新解释,非常粗暴,所以风险很高,慎重使用。#include <iostream> int main(){ char str[]="hello world!"; float *p = reinterpret_cast<float*>(str); std::cout << *p << std::endl; // 1.14314e+27 return 0; }
至此,本文结束。
更多相关内容 -
static_cast,dynamic_cast,reinterpret_cast,const_cast的区别及用法详解
2020-12-31 15:13:012.dynamic_cast提供安全的转换如果两个指针不存在继承关系转换会失败返回空指针,如果你提供一个错误的指针那样会发生内存访问异常,因为它会去比较两个类型的虚函数表。虚函数表的指针一般放在对象指针最开始的四字... -
C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结
2020-09-04 03:29:53主要介绍了C++中的类型转换static_cast、dynamic_cast、const_cast和reinterpret_cast总结,需要的朋友可以参考下 -
dynamic_cast_benchmark:C ++中dynamic_cast的三种不同实现的性能比较
2021-03-29 15:08:48dynamic_cast_benchmark 三种不同的dynamic_cast实现的性能比较请参阅我的博客文章: 汇编: git submodule initgit submodule updatemake./dynamic_cast_benchmark 目标编译器:clang版本13.0.0 以下是dynamic_cast... -
static_cast,dynamic_cast,reinterpret_cast和const_cast的区别详解
2020-12-25 22:50:59C-style cast举例: int i; double d; i = (int) d;上面的代码就是本来为double类型的d,通过(int)d将其转换成整形值,并将该值赋给整形变量i (注意d本身的值并没有发生改变)。这就是典型的c-style类型转换。下面... -
Priori:快速的C ++ dynamic_cast <>替代
2021-05-03 09:22:55C ++快速dynamic_cast <>替代 版权所有2013-2021 John Farrier Apache 2.0许可 概述 Priori是一个特殊的基类,当dynamic_cast<>本身已成为瓶颈时,它可以促进非常快速的dynamic_cast<>替代方案。 特别是在... -
c++ dynamic_cast与static_cast使用方法示例
2020-09-04 21:41:37本文用示例讲解了dynamic_cast、static_cast子类与基类之间转换功能的使用方法 -
浅谈static_cast、dynamic_cast、const_cast、reinterpret_cast用法
2022-07-20 15:44:22显式转换,在C++中有四个类型的转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。 1. static_cast用法 转换格式: 将expression转换为type_id类型,主要用于非多态类型之间的转换; static_cast...C++中的类型转换分两种:隐式类型转换和显式类型转换。
隐式转换,是标准的转换,很多时候是默认情况下由编译器进行转换;
显式转换,在C++中有四个类型的转换符:static_cast、dynamic_cast、const_cast、reinterpret_cast。
1. static_cast用法
转换格式:
- 将expression转换为type_id类型,主要用于非多态类型之间的转换;
- static_cast转换,不能转换掉expression的const、volatile、和_unaligned属性
static_cast<type_id>(expression)
- 场景1,用于类层次结构中,基类和子类之间的指针或引用的转换
【1】上行转换,子类指针或引用转父类,这种转换是安全的。
多态类型之间转换:使用static_cast和使用dynamic_cast效果一样;
非多态类型之间转换:只能使用static_cast,使用dynamic_cast会编译报错;
//先定义一个父类A,和子类B class A { public: virtual void Func() { cout << "A::Func()" << endl; } }; class B : public A { public: void Func() override { cout << "B::Func()" << endl; } }; int main() { A* pa = new B; A* a = static_cast<B*>(pb);//ok,转换是安全的 B* pb = new B; A* a = static_cast<B*>(pb);//ok,转换是安全的 return 0; }
【2】下行转换,父类指针或引用转子类,这种转换是不安全的
int main() { //B* pb = new A; //error,编译报错,无法从A*转换为B* A* pa = new A; B* b = static_cast<B*>(pa); //ok,编译无误,b != nullptr,这是不安全的,没有做类型检查 return 0; }
- 场景2,用于基本数据类型之间的转换,如把int转成char,把int转换成enum等等,这种转换是不安全的
char转int,是安全的
int iVar1 = 10; char cVar1 = 'a'; iVar1 = static_cast<int>(cVar1); cout << iVar1 << endl;
int转char,是不安全的,由ASSIC表得出,只有int[32,126]区间,转换才是安全的
int iVar2 = 10; char cVar2 = 'a'; cVar2 = static_cast<char>(iVar2); cout << cVar2 << endl;
- 场景3,把void指针转换成目标类型,这种转换是及其不安全的,编译报错
int a = 10; void* pa = &a; int b = static_cast<int>(pa); cout << b << endl; float c = static_cast<float>(pa); cout << c << endl;
- 另外,static_cast转换,不能转换掉expression的const、volatile、和_unaligned属性
const int iVar = 110; int* pVar1 = static_cast<int*>(&iVar);//编译报错 const int* pVar2 = static_cast<const int*>(&iVar);//编译无误,通过
2. dynamic_cast用法
转换格式:
- 将expression转换为type-id类型,type-id必须是类的指针或引用或void*;
- 如果type-id是指针类型,那么expression也必须是一个指针;
- 如果type-id是引用类型,那么expression也必须是一个引用;
- dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换;其中进行上行转换时,dynamic_cast和static_cast的效果一样;进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更安全;
- 在多态类型之间转换主要使用dynamic_cast,因为类型提供了运行时信息。
dynamic_cast<type_id>(expression)
- 场景1,用于类层次结构中,基类和子类之间的指针或引用的转换
【1】上行转换(单继承),子类指针或引用转父类,这种转换是安全的。
多态类型之间转换:使用static_cast和使用dynamic_cast效果一样;
非多态类型之间转换:只能使用static_cast,使用dynamic_cast会编译报错;
class A { public: virtual void Func(){cout << "A::Func()" << endl;} }; class B: public A { public: virtual void Func() override{cout << "B::Func()" << endl;} }; int main() { B* pb = new B; A* a1 = dynamic_cast<A*>(pb); //OK a1->Func(); A* pa = new B; A* a2 = dynamic_cast<A*>(pa); //OK a2->Func(); return 0; }
如果Func为virtual,输出结果:
如果Func为非virtual,输出结果:
【2】上行转换(多重继承),子类指针或引用转父类,这种转换是安全的
class A { public: virtual void Func(){} }; class B: public A { public: virtual void Func() override{} }; class C : public B { public: virtual void Func() override{} }; int main() { C* c = new C; B* b = dynamic_cast<B*>(c); //OK A* a = dynamic_cast<A*>(c); //OK }
- 场景2,将类转换为void*,A类和B类中必须包含虚函数。
原因,类中存在虚函数,说明有想让基类指针或引用指向派生类对象的情况,此时转换才有意义;由于运行时类型检查需要运行时类型信息(该运行信息存储在类的虚函数表中),所以只有定义了虚函数的类才有虚函数表。
class A { public: virtual void Func() {} //注意关键字virtual // ...... }; class B : public A { public: virtual void Func() {} //注意关键字virtual // ...... }; int main() { A *pA = new A; B *pB = new B; void *pV = dynamic_cast<void *>(pA); // pV points to an object of A pV = dynamic_cast<void *>(pB); // pV points to an object of B system("pause"); return 0; }
去掉virtual关键字,会编译报错
- 场景3,如果expression类型是type-id的基类,使用dynamic_cast进行转换时,在运行时会检查expression是否真正的指向一个type-id类型的对象。如果是,则能进行正确的转换,得到真正的值;否则返回NULL;如果是引用,则在运行时就会抛出异常。
【1】下行转换(单继承),父类指针或引用转子类,会做类型安全检查,这种转换是安全的
class A { public: virtual void Func(){cout << "A::Func()" << endl;} }; class B: public A { public: virtual void Func() override{cout << "B::Func()" << endl;} }; int main() { //B* pb = new A; //error,编译报错,无法从父类A*转换为子类B* /* * 由父类A*转换子类B*,使用dynamic_cast能做到安全检查,转换失败会返回null; * 使用static_cast不安全 */ A* pa1 = new B; B* b1 = dynamic_cast<B*>(pa1); //ok,编译无误,b != nullptr if (nullptr != b1) { b1->Func(); } A* pa2 = new A; B* b2 = dynamic_cast<B*>(pa2); //ok,编译无误,b = nullptr if (nullptr != b2) { b2->Func(); } return 0; }
【2】 对于一些复杂继承关系,使用dynamic_cast进行转换是存在一些陷阱的
如下做法存在陷阱,
class A { virtual void Func() = 0; }; class B : public A { void Func() { cout << "B::Func()" << endl; } }; class C : public A { void Func() { cout << "C::Func()" << endl; }; }; class D : public B, public C { void Func() { cout << "D::Func()" << endl; } }; int main() { D *pD = new D; /* * B和C都继承了A,并且都实现了虚函数Func,导致在进行转换时,无法进行抉择应该向哪个A进行转换 */ A *pA = dynamic_cast<A *>(pD); // pA = NULL //pA->Func(); system("pause"); return 0; }
正确的做法是,像多重继承关系这种情况,需要把子类逐步转换到父类
int main() { D *pD = new D; B *pB = dynamic_cast<B *>(pD); A *pA = dynamic_cast<A *>(pB); return 0; }
3. const_cast用法
转换格式:const_cast用来将类型的const、volatile和_unaligned属性移除。
- 常量指针被转换为非常量指针,并且仍然指向原来的对象;
- 常量引用被转换为非常量引用,并且仍然引用原来的对象;
- 不能直接对非指针和非引用的变量使用const_cast操作符去直接移除它的const、volatile和__unaligned属性。
const_cast <type-id> (expression)
- 场景1,常量指针转非常量指针
class A { public: A() :m_iA(10) {} int m_iA; }; int main() { //常量指针转非常量指针 const A *pA = new A; //pA->m_iA = 100; //error,pA常量指针,指向的内容不能修改 cout << pA->m_iA << endl; A *pB = const_cast<A*>(pA); //去const属性 pB->m_iA = 100; //通过指针,修改值 //指针pA和pB指向同一个对象 cout << pA->m_iA << endl; cout << pB->m_iA << endl; return 0; }
- 场景2,指针常量转非指针常量
class A { public: A() :m_iA(10) {} int m_iA; }; int main() { //常量指针转非常量指针 A * const pA1 = new A; pA1->m_iA = 100; //ok,pA是指针常量,指向的内容可以修改 cout << pA1->m_iA << endl; A *pA2 = new A; //pA1 = pA2; //error,pA是指针常量,指向的地址不能修改 A *pB = const_cast<A*>(pA1); //去const属性 pB = pA2; //通过指针,修改值 pB->m_iA = 111; //指针pA和pB指向同一个对象 cout << pA1->m_iA << endl; cout << pA2->m_iA << endl; cout << pB->m_iA << endl; return 0; }
- 场景3,常量引用转非常量引用
int main() { const int &num = 10; //num = 100; //error,不能给常量赋值 int &num2 = const_cast<int&>(num); num2 = 100; return 0; }
- 场景4,不能给非常量指针和引用使用const_cast
int main() { const int num1 = 10; //int num2 = const_cast<int>(num1); //error,编译报错,无法从“const int”转换为“int” return 0; }
4. reinterpret_cast用法
转换格式:
reinterpret_cast <type-id> (expression)
reinterpret_cast后的尖括号中的type-id类型必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
-
C/C++中的数据类型转换()/static_cast/dynamic_cast/const_cast/reinterpret_cast
2021-07-12 00:27:36文章目录 前言 数据类型自动转换 C语言中的强制类型转换 C++中的强制类型转换 static_cast dynamic_cast const_cast reinterpret_cast 强转关键字的选择 总结 前言 C/C++属于静态语言,也就是在编译时变量的数据类型...前言
C/C++属于静态语言,也就是在编译时变量的数据类型即可确定的强类型语言。当不同的数据类型在一起运算或者相互赋值的时候,就需要进行数据类型转换。不同数据类型占用的内存空间不同,而各种数据类型的转换时有规则的,一种通用的规则就是“小转大”自动进行,“大转小”需要强制执行。这里的“大”和“小”指的是数据范围。
为什么会有数据范围大小的区别呢?这就和饭店里的盘子一样,不同的菜肴通常使用不同的盘子,盘子有大有小,如果把小盘子里的菜装到大盘子里没有问题,但是把大盘子里的菜放到小盘子中就会溢出来,假设都使用大盘子就不会产生溢出的问题,但是这样会产生空间的浪费。而C/C++中不同类型的变量占用的内存空间不同与这些盘子非常相似,当范围小的变量赋值给范围大的变量时没有问题,但是反过来也会出现溢出。
数据类型自动转换
当不同类型的变量同时运算时就会发生数据类型的自动转换,以常见的
char
、short
、int
、long
、float
、double
这些类型为例,如果char
和int
两个类型的变量相加时,就会把char
先转换成int
再进行加法运算,如果是int
和double
类型的变量相乘就会把int
转换成double
再进行运算。自动转换的行为如下图所示,方向是从左往右自动进行:
C语言中的强制类型转换
前面说了自动转换,从这里开始聊聊强制类型转换,需要强制类型转换往往程序不那么智能了,需要人工进行干预。比如把一个
int
类型的变量赋值给char
类型的变量,或者说把两个int
相乘时可能会得到一个很大的数,所以需要先把int
强制转换成double
计算防止溢出。强制类型转换的格式为:
(new_type_name) expression
,其中new_type_name
为新类型名称,expression
为表达式。例如:int val = 65535; char ch = (char)val;
或者
int m = 2147483647, n = 100; double result = (double)m * n;
无论是自动的类型转换还是强制类型转换,都只是为了本次操作或运算而进行的临时转换,转换的结果也会保存到临时的内存空间内,不会改变数据本来的类型或者具体的值。
有些强制类型转换是对原有数据的重新解释,比如:
void test(void* p) { char* buffer = (char*)p; // ... }
void*
类型的变量p,经过强制类型转换以后变成了char
类型的指针,此后就可以把这段内存空间当成字符数组来处理了。C++中的强制类型转换
在C++语言中新增了四个用于强制类型转换的关键字,分别是
static_cast
、dynamic_cast
,const_cast
、 和reinterpret_cast
,使用语法为xxxx_cast<new_type_name>(expression)
。相比于C语言中使用小括号
()
来完成强制类型转换,C++中这几个关键字的引入能更清晰的表明它要完成强制类型转换的意图,容易暴露出隐藏的问题。其实很长一段时间以来,我对于这四种强转方式区分的不是很清晰,其中
const_cast
的功能还比较容易辨别,但是另外3种经常混作一团,所以才有了这篇总结,而仔细学习后才发现,这4种强转关键字的区别就在他们的名字上,下面逐个来看一下。static_cast
这个关键字的作用主要表现在
static
上,是一种静态的转换,在编译期就能确定的转换,可以完成C语言中的强制类型转换中的大部分工作,但需要注意的是,它不能转换掉表达式的const
、volitale
或者__unaligned
属性。它主要有以下几种用法:
- 用于基本数据类型之间的转换,如把
int
转换成char
,把int
转换成double
等。
int val = 110119; char c = static_cast<char>(val); double d = static_cast<double>(val);
- 将表达式转换成
void
类型,并将转换后的结果丢弃
int val = 110119; static_cast<void>(val);
- 可以用于
void*
和其他指针类类型之间的转换,但是不能用于两个无关指针类型的直接转换
// 正常转换 int *p = new int; void* p1 = static_cast<void*>(p); char* p2 = static_cast<char*>(p1); // 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’ char* p3 = static_cast<char*>(p);
- 可以用于类继承结构中基类和派生类之间指针或引用的转换,向上转型安全,向下转型由于没有动态类型检查,是不安全的。
struct B { }; struct D : B { }; D d; B& rb = d; D& rd = static_cast<D&>(rb);
- 如果涉及左值到右值、数组到指针或函数到指针的转换,也可以通过static_cast显式执行。
template<typename _Tp> inline typename std::remove_reference<_Tp>::type&& move(_Tp&& __t) { return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
dynamic_cast
从名字上看,这个关键字与
static_cast
的静态转换是对立的,这是一个“动态”转换函数,只能对指针和引用的进行转换,并且只用于类继承结构中基类和派生类之间指针或引用的转换,可以进行向上、向下,或者横向的转换。相比于
static_cast
的编译时转换,dynamic_cast
的转换还会在运行时进行类型检查,转换的条件也比较苛刻,必须有继承关系的类之间才能转换,并且在基类中有虚函数才可以,有一种特殊的情况就是可以把类指针转换成void*
类型。关于使用中的常见问题,参考以下几种情况:
- 普通类型的指针无法转换
int val = 100; int *p = &val; // 编译失败 //error: cannot dynamic_cast ‘p’ (of type ‘int*’) to type ‘char*’ (target is not pointer or reference to class) char* pc = dynamic_cast<char*>(p);
- 继承结构中基类里面没有虚函数无法转换
struct B { }; struct D : B { }; D d; B* pb = &d; // 编译失败 //error: cannot dynamic_cast ‘pb’ (of type ‘struct test1()::B*’) to type ‘struct test1()::D*’ (source type is not polymorphic) D* pd = dynamic_cast<D*>(pb)
- 指针或引用转换的类型不是正确的类型,如果参数类型是指针会返回目标类型空指针,如果参数类型是引用则会抛出
std::bad_cast
异常。
struct B { virtual void test() {} }; struct D : B { }; B d; B* pb = &d; D* pd = dynamic_cast<D*>(pb); // 编译成功,但是pb指针指向的类型是 B,向下转型失败,输出结果是0,也就是空指针 std::cout << pd << std::endl;
- 一个正常转换的例子,包含向上、向下、横向转换
struct B { virtual void test() {} }; struct D1 : virtual B { }; struct D2 : virtual B { }; struct MD : D1, D2 { }; D1* pd1 = new MD(); std::cout << pd1 << std::endl; // 向上转型 B* pb = dynamic_cast<B*>(pd1); std::cout << pb << std::endl; // 向下转型 MD* pmd = dynamic_cast<MD*>(pd1); std::cout << pmd << std::endl; // 横向转型 D2* pd2 = dynamic_cast<D2*>(pd1); std::cout << pd2 << std::endl;
运行结果如下,在横向转换时指针发生了变化,可以看出
dynamic_cast
不是简单的数据强转,还进行了指针的偏移:albert@home-pc:/mnt/d/testconvert$ g++ cppconvert.cpp albert@home-pc:/mnt/d/testconvert$ ./a.out 0x15c0c40 0x15c0c40 0x15c0c40 0x15c0c48
const_cast
在C/C++中,const限定符通常被用来限定变量,用于表示该变量的值不能被修改,这种限定可以避免程序员犯一些初级错误,但同时也造成了一些不便,比如一些已有函数要求非常量指针,但是掉用这些函数的接口函数中都传递了常量指针,这时候就要对指针类型去常量化。
但需要特别注意的是
const_cast
不能去除变量的常量性,只能用来去除指向常数对象的指针或引用的常量性,且去除常量性的对象必须为指针或引用。常量指针被转化成非常量指针,并且仍然指向原来的对象,常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象可能被转换成非常量对象。
- 尝试去除非指针和引用的类型的常量性会编译失败
const int i = 6; // 编译错误 // int j = const_cast<int>(i);
- 企图用一个指针来修改常量:
const int val = 6; //编译错误 //error: invalid conversion from ‘const int*’ to ‘int*’ [-fpermissive] int* cp = &val;
- 修改一个指针的常量性:
const int val = 6; std::cout << "&val=" << &val << ", val=" << val << std::endl; const int* cp = &val; int *p = const_cast<int*>(cp); *p = 2; std::cout << "&val=" << &val << ", val=" << val << std::endl; std::cout << "p=" << p << ", *p=" << *p << std::endl;
运行结果如下:
&val=0x7ffff7446bd4, val=6 &val=0x7ffff7446bd4, val=6 p=0x7ffff7446bd4, *p=2
运行之后,变量
p
指向了变量val
地址,并改变了地址所指向的内存数据,但是打印val
的值并没有发生变化,这是因为val
作为常量在编译期使用它的地方就进行了替换,接下来再看另一种情况。int init = 6; const int val = init; std::cout << "&val=" << &val << ", val=" << val << std::endl; const int* cp = &val; int *p = const_cast<int*>(cp); *p = 2; std::cout << "&val=" << &val << ", val=" << val << std::endl; std::cout << "p=" << p << ", *p=" << *p << std::endl;
代码逻辑不变,只在开始的位置使用
init
这个变量来代替6
这个常数,运行结果如下:val=0x7fffe8c71fa0, val=6 &val=0x7fffe8c71fa0, val=2 p=0x7fffe8c71fa0, *p=2
运行之后
val
本身的变化也应用到了使用它的地方,这里的编译器替换已经不起作用了。实际上,使用const_cast通常是一种无奈之举,利用const_cast去掉指针或引用的常量性并且去修改原始变量的数值,这是一种非常不好的行为,如果可以的话,尽可能在程序设计阶段就规避这种情况。
reinterpret_cast
它被用于不同类型指针或引用之间的转换,或者指针和整数之间的转换,是对比特位的简单拷贝并重新解释,因此在使用过程中需要特别谨慎,比如前面提到的一个例子,
static_cast
不能将int*
直接强转成char*
,使用reinterpret_cast就可以办到。- 不同基础类型指针类型之间转换:
int *p = new int; // 编译失败 //error: invalid static_cast from type ‘int*’ to type ‘char*’ char* p1 = static_cast<char*>(p); // 编译成功 char* p2 = reinterpret_cast<char*>(p1);
- 基础类型指针与类对象指针之间的转换:
struct B { int val;}; B b{100}; std::cout << "b.val=" << b.val << std::endl; int* p = reinterpret_cast<int*>(&b); std::cout << "*p=" << *p << std::endl;
运行之后可以得到
*p
的值为100,也就是重新解释了变量b
的地址为整型指针。- 将地址值转换成整数
struct B { int val;}; B b{101}; std::cout << "&b=" << &b << std::endl; long addr = reinterpret_cast<long>(&b); std::cout << "addr=" << addr << std::endl;
运行结果如下:
&b=0x7ffffdc4f270 addr=140737450930800
这里的地址
0x7ffffdc4f270
被解释成了整数140737450930800
,因为涉及到字节序,这也是很多文章提到的reinterpret_cast
不具备一致性的问题,我们需要知道这一个点,只要代码不依赖主机字节序就没有问题。强转关键字的选择
好几个关键字,并且有些功能还是重复的,那么究竟该选哪一个呢?这个真得按照经验来选,我建议使用排除法,按照
const_cast -> dynamic_cast -> reinterpret_cast -> static_cast
的顺序带入选择。-
先看是不是要去掉指针或引用的常量属性,如果是只能选择
const_cast
-
再看转换的是不是继承体系下的多态结构,如果是这种结构下的指针和引用的转换最好使用
dynamic_cast
-
接着看是不是偏底层的代码,需要将无关类型指针进行转换,或者指针与整数之间进行转换,如果是则选择
reinterpret_cast
-
前三种情况都不满足,那就只能使用
static_cast
了
总结
- C/C++中不同数据类型进行运算或者赋值的时候会发生数据转换,这种转换有些是自动进行的,有些需要进行显示的强制类型转换
- 在C语言中强制类型转换写成
(new_type_name) expression
的形式,new_type_name
是要转换的目标类型,expression
是待转换的表达式 - 在C++中强制类型转换通过更明显的关键字来完成,分别是
static_cast
、dynamic_cast
,const_cast
、 和reinterpret_cast
static_cast
是静态转换,在编译期完成完成转换,与C语言中的强制类型转换重合度最高dynamic_cast
是动态转换,在运行时转换会进行检查,必须用在有继承关系的多态结构中const_cast
是常量转换,用于取出指针或引用的常量属性,但是尽量通过设计杜绝它的使用场景reinterpret_cast
是一种内存数据的重新解释,比较原始,开发者使用它的时候应该明确的知道自己在做什么
==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==
今夜的雨,好美~
- 用于基本数据类型之间的转换,如把
-
C++ static_cast、dynamic_cast、const_cast和reinterpret_cast(四种类型转换运算符)
2022-02-13 09:26:58C++ static_cast、dynamic_cast、const_cast和reinterpret_cast(四种类型转换运算符) 隐式类型转换是安全的,显式类型转换是有风险的,C语言之所以增加强制类型转换的语法,就是为了强调风险,让程序员意识到自己...C++ static_cast、dynamic_cast、const_cast和reinterpret_cast(四种类型转换运算符)
隐式类型转换是安全的,显式类型转换是有风险的,C语言之所以增加强制类型转换的语法,就是为了强调风险,让程序员意识到自己在做什么。
但是,这种强调风险的方式还是比较粗放,粒度比较大,它并没有表明存在什么风险,风险程度如何。再者,C风格的强制类型转换统一使用( ),而( )在代码中随处可见,所以也不利于使用文本检索工具(例如 Windows 下的 Ctrl+F、Linux 下的 grep 命令、Mac 下的 Command+F)定位关键代码。
为了使潜在风险更加细化,使问题追溯更加方便,使书写格式更加规范,C++ 对类型转换进行了分类,并新增了四个关键字来予以支持,它们分别是:
关键字 说明 static_cast 用于良性转换,一般不会导致意外发生,风险很低。 const_cast 用于 const 与非 const、volatile 与非 volatile 之间的转换。 reinterpret_cast 高度危险的转换,这种转换仅仅是对二进制位的重新解释,不会借助已有的转换规则对数据进行调整,但是可以实现最灵活的 C++ 类型转换。 dynamic_cast 借助 RTTI,用于类型安全的向下转型(Downcasting)。 这四个关键字的语法格式都是一样的,具体为:
xxx_cast<newType>(data)
newType 是要转换成的新类型,data 是被转换的数据。例如,老式的C风格的 double 转 int 的写法为:
double scores = 95.5; int n = (int)scores; C++ 新风格的写法为: double scores = 95.5; int n = static_cast<int>(scores);
static_cast 关键字
static_cast 只能用于良性转换,这样的转换风险较低,一般不会发生什么意外,例如:
原有的自动类型转换,例如 short 转 int、int 转 double、const 转非 const、向上转型等;
void 指针和具体类型指针之间的转换,例如void *转int *、char *转void *等;
有转换构造函数或者类型转换函数的类与其它类型之间的转换,例如 double 转 Complex(调用转换构造函数)、Complex 转 double(调用类型转换函数)。需要注意的是,static_cast 不能用于无关类型之间的转换,因为这些转换都是有风险的,例如:
两个具体类型指针之间的转换,例如int *转double *、Student *转int *等。不同类型的数据存储格式不一样,长度也不一样,用 A 类型的指针指向 B 类型的数据后,会按照 A 类型的方式来处理数据:如果是读取操作,可能会得到一堆没有意义的值;如果是写入操作,可能会使 B 类型的数据遭到破坏,当再次以 B 类型的方式读取数据时会得到一堆没有意义的值。
int 和指针之间的转换。将一个具体的地址赋值给指针变量是非常危险的,因为该地址上的内存可能没有分配,也可能没有读写权限,恰好是可用内存反而是小概率事件。
static_cast 也不能用来去掉表达式的 const 修饰和 volatile 修饰。换句话说,不能将 const/volatile 类型转换为非 const/volatile 类型。
static_cast 是“静态转换”的意思,也就是在编译期间转换,转换失败的话会抛出一个编译错误。
下面的代码演示了 static_cast 的正确用法和错误用法:
#include <iostream> #include <cstdlib> using namespace std; class Complex{ public: Complex(double real = 0.0, double imag = 0.0): m_real(real), m_imag(imag){ } public: operator double() const { return m_real; } //类型转换函数 private: double m_real; double m_imag; }; int main(){ //下面是正确的用法 int m = 100; Complex c(12.5, 23.8); long n = static_cast<long>(m); //宽转换,没有信息丢失 char ch = static_cast<char>(m); //窄转换,可能会丢失信息 int *p1 = static_cast<int*>( malloc(10 * sizeof(int)) ); //将void指针转换为具体类型指针 void *p2 = static_cast<void*>(p1); //将具体类型指针,转换为void指针 double real= static_cast<double>(c); //调用类型转换函数 //下面的用法是错误的 float *p3 = static_cast<float*>(p1); //不能在两个具体类型的指针之间进行转换 p3 = static_cast<float*>(0X2DF9); //不能将整数转换为指针类型 return 0; }
const_cast 关键字
const_cast 比较好理解,它用来去掉表达式的 const 修饰或 volatile 修饰。换句话说,const_cast 就是用来将 const/volatile 类型转换为非 const/volatile 类型。
下面我们以 const 为例来说明 const_cast 的用法:
#include <iostream> using namespace std; int main(){ const int n = 100; int *p = const_cast<int*>(&n); *p = 234; cout<<"n = "<<n<<endl; cout<<"*p = "<<*p<<endl; return 0; }
运行结果:
n = 100 *p = 234
&n用来获取 n 的地址,它的类型为const int *,必须使用 const_cast 转换为int *类型后才能赋值给 p。由于 p 指向了 n,并且 n 占用的是栈内存,有写入权限,所以可以通过 p 修改 n 的值。
有读者可能会问,为什么通过 n 和 *p 输出的值不一样呢?这是因为 C++ 对常量的处理更像是编译时期的#define,是一个值替换的过程,代码中所有使用 n 的地方在编译期间就被替换成了 100。换句话说,第 8 行代码被修改成了下面的形式:
cout<<"n = "<<100<<endl;
这样以来,即使程序在运行期间修改 n 的值,也不会影响 cout 语句了。
使用 const_cast 进行强制类型转换可以突破 C/C++ 的常数限制,修改常数的值,因此有一定的危险性;但是程序员如果这样做的话,基本上会意识到这个问题,因此也还有一定的安全性。
reinterpret_cast 关键字
reinterpret 是“重新解释”的意思,顾名思义,reinterpret_cast 这种转换仅仅是对二进制位的重新解释,不会借助已有的转换规则对数据进行调整,非常简单粗暴,所以风险很高。
reinterpret_cast 可以认为是 static_cast 的一种补充,一些 static_cast 不能完成的转换,就可以用 reinterpret_cast 来完成,例如两个具体类型指针之间的转换、int 和指针之间的转换(有些编译器只允许 int 转指针,不允许反过来)。
下面的代码代码演示了 reinterpret_cast 的使用:
#include <iostream> using namespace std; class A{ public: A(int a = 0, int b = 0): m_a(a), m_b(b){} private: int m_a; int m_b; }; int main(){ //将 char* 转换为 float* char str[]="http://c.biancheng.net"; float *p1 = reinterpret_cast<float*>(str); cout<<*p1<<endl; //将 int 转换为 int* int *p = reinterpret_cast<int*>(100); //将 A* 转换为 int* p = reinterpret_cast<int*>(new A(25, 96)); cout<<*p<<endl; return 0; }
运行结果:
3.0262e+29 25
可以想象,用一个 float 指针来操作一个 char 数组是一件多么荒诞和危险的事情,这样的转换方式不到万不得已的时候不要使用。将A转换为int,使用指针直接访问 private 成员刺穿了一个类的封装性,更好的办法是让类提供 get/set 函数,间接地访问成员变量。
dynamic_cast 关键字
dynamic_cast 用于在类的继承层次之间进行类型转换,它既允许向上转型(Upcasting),也允许向下转型(Downcasting)。向上转型是无条件的,不会进行任何检测,所以都能成功;向下转型的前提必须是安全的,要借助 RTTI 进行检测,所有只有一部分能成功。
dynamic_cast 与 static_cast 是相对的,dynamic_cast 是“动态转换”的意思,static_cast 是“静态转换”的意思。dynamic_cast 会在程序运行期间借助 RTTI 进行类型转换,这就要求基类必须包含虚函数;static_cast 在编译期间完成类型转换,能够更加及时地发现错误。
dynamic_cast 的语法格式为:
dynamic_cast <newType> (expression)
newType 和 expression 必须同时是指针类型或者引用类型。换句话说,dynamic_cast 只能转换指针类型和引用类型,其它类型(int、double、数组、类、结构体等)都不行。
对于指针,如果转换失败将返回 NULL;对于引用,如果转换失败将抛出std::bad_cast异常。
1) 向上转型(Upcasting)
向上转型时,只要待转换的两个类型之间存在继承关系,并且基类包含了虚函数(这些信息在编译期间就能确定),就一定能转换成功。因为向上转型始终是安全的,所以 dynamic_cast 不会进行任何运行期间的检查,这个时候的 dynamic_cast 和 static_cast 就没有什么区别了。
「向上转型时不执行运行期检测」虽然提高了效率,但也留下了安全隐患,请看下面的代码:
#include <iostream> #include <iomanip> using namespace std; class Base{ public: Base(int a = 0): m_a(a){ } int get_a() const{ return m_a; } virtual void func() const { } protected: int m_a; }; class Derived: public Base{ public: Derived(int a = 0, int b = 0): Base(a), m_b(b){ } int get_b() const { return m_b; } private: int m_b; }; int main(){ //情况① Derived *pd1 = new Derived(35, 78); Base *pb1 = dynamic_cast<Derived*>(pd1); cout<<"pd1 = "<<pd1<<", pb1 = "<<pb1<<endl; cout<<pb1->get_a()<<endl; pb1->func(); //情况② int n = 100; Derived *pd2 = reinterpret_cast<Derived*>(&n); Base *pb2 = dynamic_cast<Base*>(pd2); cout<<"pd2 = "<<pd2<<", pb2 = "<<pb2<<endl; cout<<pb2->get_a()<<endl; //输出一个垃圾值 pb2->func(); //内存错误 return 0; }
情况①是正确的,没有任何问题。对于情况②,pd 指向的是整型变量 n,并没有指向一个 Derived 类的对象,在使用 dynamic_cast 进行类型转换时也没有检查这一点,而是将 pd 的值直接赋给了 pb(这里并不需要调整偏移量),最终导致 pb 也指向了 n。因为 pb 指向的不是一个对象,所以get_a()得不到 m_a 的值(实际上得到的是一个垃圾值),pb2->func()也得不到 func() 函数的正确地址。
pb2->func()得不到 func() 的正确地址的原因在于,pb2 指向的是一个假的“对象”,它没有虚函数表,也没有虚函数表指针,而 func() 是虚函数,必须到虚函数表中才能找到它的地址。
2) 向下转型(Downcasting)
向下转型是有风险的,dynamic_cast 会借助 RTTI 信息进行检测,确定安全的才能转换成功,否则就转换失败。那么,哪些向下转型是安全地呢,哪些又是不安全的呢?下面我们通过一个例子来演示:
#include <iostream> using namespace std; class A{ public: virtual void func() const { cout<<"Class A"<<endl; } private: int m_a; }; class B: public A{ public: virtual void func() const { cout<<"Class B"<<endl; } private: int m_b; }; class C: public B{ public: virtual void func() const { cout<<"Class C"<<endl; } private: int m_c; }; class D: public C{ public: virtual void func() const { cout<<"Class D"<<endl; } private: int m_d; }; int main(){ A *pa = new A(); B *pb; C *pc; //情况① pb = dynamic_cast<B*>(pa); //向下转型失败 if(pb == NULL){ cout<<"Downcasting failed: A* to B*"<<endl; }else{ cout<<"Downcasting successfully: A* to B*"<<endl; pb -> func(); } pc = dynamic_cast<C*>(pa); //向下转型失败 if(pc == NULL){ cout<<"Downcasting failed: A* to C*"<<endl; }else{ cout<<"Downcasting successfully: A* to C*"<<endl; pc -> func(); } cout<<"-------------------------"<<endl; //情况② pa = new D(); //向上转型都是允许的 pb = dynamic_cast<B*>(pa); //向下转型成功 if(pb == NULL){ cout<<"Downcasting failed: A* to B*"<<endl; }else{ cout<<"Downcasting successfully: A* to B*"<<endl; pb -> func(); } pc = dynamic_cast<C*>(pa); //向下转型成功 if(pc == NULL){ cout<<"Downcasting failed: A* to C*"<<endl; }else{ cout<<"Downcasting successfully: A* to C*"<<endl; pc -> func(); } return 0; }
运行结果:
Downcasting failed: A* to B* Downcasting failed: A* to C* ------------------------- Downcasting successfully: A* to B* Class D Downcasting successfully: A* to C* Class D
这段代码中类的继承顺序为:A --> B --> C --> D。pa 是A类型的指针,当 pa 指向 A 类型的对象时,向下转型失败,pa 不能转换为B或C类型。当 pa 指向 D 类型的对象时,向下转型成功,pa 可以转换为B或C*类型。同样都是向下转型,为什么 pa 指向的对象不同,转换的结果就大相径庭呢?
我们讲到了有虚函数存在时对象的真实内存模型,并且也了解到,每个类都会在内存中保存一份类型信息,编译器会将存在继承关系的类的类型信息使用指针“连接”起来,从而形成一个继承链(Inheritance Chain),也就是如下图所示的样子:
当使用 dynamic_cast 对指针进行类型转换时,程序会先找到该指针指向的对象,再根据对象找到当前类(指针指向的对象所属的类)的类型信息,并从此节点开始沿着继承链向上遍历,如果找到了要转化的目标类型,那么说明这种转换是安全的,就能够转换成功,如果没有找到要转换的目标类型,那么说明这种转换存在较大的风险,就不能转换。
对于本例中的情况①,pa 指向 A 类对象,根据该对象找到的就是 A 的类型信息,当程序从这个节点开始向上遍历时,发现 A 的上方没有要转换的 B 类型或 C 类型(实际上 A 的上方没有任何类型了),所以就转换败了。对于情况②,pa 指向 D 类对象,根据该对象找到的就是 D 的类型信息,程序从这个节点向上遍历的过程中,发现了 C 类型和 B 类型,所以就转换成功了。
总起来说,dynamic_cast 会在程序运行过程中遍历继承链,如果途中遇到了要转换的目标类型,那么就能够转换成功,如果直到继承链的顶点(最顶层的基类)还没有遇到要转换的目标类型,那么就转换失败。对于同一个指针(例如 pa),它指向的对象不同,会导致遍历继承链的起点不一样,途中能够匹配到的类型也不一样,所以相同的类型转换产生了不同的结果。
从表面上看起来 dynamic_cast 确实能够向下转型,本例也很好地证明了这一点:B 和 C 都是 A 的派生类,我们成功地将 pa 从 A 类型指针转换成了 B 和 C 类型指针。但是从本质上讲,dynamic_cast 还是只允许向上转型,因为它只会向上遍历继承链。造成这种假象的根本原因在于,派生类对象可以用任何一个基类的指针指向它,这样做始终是安全的。本例中的情况②,pa 指向的对象是 D 类型的,pa、pb、pc 都是 D 的基类的指针,所以它们都可以指向 D 类型的对象,dynamic_cast 只是让不同的基类指针指向同一个派生类对象罢了。
-
C++ 强制类型转换操作符(static_cast、dynamic_cast、const_cast和reinterpret_cast)
2021-02-18 16:32:501、static_cast static_cast Operator The expression static_cast < type-id > ( expression ) converts expression to the type of type-id based solely on the types present in the expression. ... -
static_cast和dynamic_cast的区别
2022-05-30 17:34:23static_cast //用法: static_cast < type-id > ( exdivssion ) 该运算符把exdivssion转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它主要有如下几种用法: ①用于类层次结构中基类和子类... -
static_cast, dynamic_cast, const_cast 和 reinterpret_cast的使用
2022-02-10 21:25:52static_cast, dynamic_cast, const_cast 和 reinterpret_cast的使用 -
static_cast和dynamic_cast
2021-07-14 14:50:41static_cast和dynamic_cast前言一、static_cast关键字(编译时类型检查)二、dynamic_cast关键字(运行时类型检查)总结 前言 在C++标准中,提供了关于类型层次转换中的两个关键字static_cast和dynamic_cast。 一... -
C++四种类型强制转换——const_cast、static_cast、dynamic_cast、reinterpret_cast
2021-12-14 10:33:52示例演示三、dynamic_cast1.基本知识2.示例演示四、reinterpret_cast1.基本知识2.示例演示 一、const_cast 1.基本知识 (1)const_cast只针对指针、引用,当然,this指针也是其中之一。 (2)const_cast的大部分使用... -
c++类型转换 const_cast、dynamic_cast、reinterpret_cast、static_cast
2022-02-02 19:36:43const_cast #include <iostream> using namespace std; /* const_cast<要转换类型>(要转换的目标) 1.去掉const属性(提供一个可以修改的接口去操作const属性的变量) 2.加上const属性(用的比较少) */... -
static_cast, dynamic_cast, const_cast and reinterpret_cast之间的区别
2022-04-26 23:46:24static_cast, dynamic_cast, const_cast and reinterpret_cast之间的区别 自己把gg上内容翻译了一下,有好多知识点都是自己不懂的,希望有大佬后面指点一下。 一、static_cast ①首先要考虑用到的投射转换。 ②作用... -
由static_cast和dynamic_cast到C++对象占用内存的全面分析
2021-01-20 05:37:34static_cast和dynamic_cast是C++的类型转换操作符。编译器隐式执行的任何类型转换都可以由static_cast显式完成,即父类和子类之间也可以利用static_cast进行转换。而dynamic_cast只能用于类之间的转换。那么dynamic_... -
Priori-快速dynamic_cast <>替代
2021-04-11 16:58:28本文讨论了dynamic_cast Priori的快速替代方案的实现和使用。 -
dynamic_cast
2021-08-08 17:12:58dynamic_cast dynamic_cast主要用于“安全地向下转型” dynamic_cast用于类继承层次间的指针或引用转换。主要用于执行“安全的向下转型”,对于向上转换,没有问题。 dynamic_cast<new_type>(expression) ... -
C/C++类型转换:reinterpret_cast、const_cast、dynamic_cast、static_cast
2020-01-28 15:36:46C++为了增强转换的可视性,引入了四种强制转换的操作符分别是static_cast、const_cast、dynamic_cast、reinterpret_cast。 一、static_cast static_cast (expression):将expression转换为type-id 类型 最... -
数据类型转换操作符:const_cast、static_cast、dynamic_cast以及reinterpret_cast
2020-09-20 20:42:05文章目录数据类型转换const_cast的用法使用const_cast...它们分别是:const_cast、static_cast、dynamic_cast以及reinterpret_cast,它们的语法形式是统一的,type_cast_operator(expression) const_cast主要用于解除 -
static_cast、dynamic_cast、 const_cast、reinpreter_cast-详解
2019-03-11 16:10:59显式类型转换-被称为“强制类型转换”(cast) C 风格: (type-id) C++风格: static_cast、dynamic_cast、reinterpret_cast、和const_cast.. 关于强制类型转换的问题,很多书都讨论过,写的最详细的是C++ 之父的... -
类型转换操作符:static_cast,dynamic_cast,const_cast,reinterpret_cast.
2021-01-31 01:48:58呵呵,今天来好好看看着几个转换操作符的用法。以前老是看着眼熟,但是用着手生。今天决定搞定这些个东西。在C语言中类型转换有几种方式:1.(expression).在表达式外边加括号,由编译器来决定怎么改变。... -
C/C++ static_cast、dynamic_cast、const_cast、reinterpret_cast 笔记整理
2022-04-22 23:50:52static_cast、dynamic_cast、const_cast、reinterpret_cast std::static_pointer_cast、std::dynamic_pointer_cast、std::const_pointer_cast、std::reinterpret_pointer_cast使用简单介绍 -
static_cast、dynamic_cast、reinpreter_cast、const_cast
2021-05-19 15:21:041. static_cast与dynamic_cast 1> static_cast运算符可用于诸如将指向基类的指针转换为指向派生类的指针之类的操作。这种转换并不总是安全的。 2> 通常,当你要将数字数据类型(如枚举转换为整数或整数)转换... -
C++的四种强制转换reinterpret_cast/const_cast/static_cast /dynamic_cast
2022-04-26 23:03:54C++的四种强制转换reinterpret_cast/const_cast/static_cast /dynamic_cast reinterpret_cast reinterpret_cast (expression) type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以用于类型之间...