IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> c++之强制类型转换 -> 正文阅读

[C++知识库]c++之强制类型转换

目录

1. static_cast ( expression )

2.?dynamic_cast < type-id > ( expression )? ?

3.?const_cast (expression)

4.reinterpret_cast < type-id > ( expression )


从vs官网上有文档:

static_cast Used for convension of nonpolymorphic types(static_cast用于非多态类型的转换).
dynamic_cast Used for conversion of polymorphic types(dynamic_cast 用于多态类型的转换).
const_cast Used to remove the const,volatile,and _unaligned attributes(用于除去const,volatile和_unaligned属性).
reinterpret_cast Used for simple reinterpretation of bits(对位的简单重新解释).

1. static_cast <type-id> ( expression )

仅基于表达式中存在的类型,将表达式转换为type-id的类型。

(a) static_cast操作符可用于将基类指针转换为派生类指针等操作。这种转换并不总是安全的;

官方示例:
// static_cast_Operator.cpp
// compile with: /LD
class B {};

class D : public B {};

void f(B* pb, D* pd) {
   D* pd2 = static_cast<D*>(pb);   // Not safe, D can have fields
                                   // and methods that are not in B.

   B* pb2 = static_cast<B*>(pd);   // Safe conversion, D always
                                   // contains all of B.
}

static_cast并没有dynamic_cast转换安全,因为static_cast没有运行时类型检查,而dynamic有;

dynamic_cast转换一个不明确的指针将会失败,而static_cast正常返回,像没有错误一样;

尽管dynamic_cast转换是安全的,但仅仅用于指针或引用类型转换,而且运行时类型转换也是一种开销;

// static_cast_Operator_2.cpp
// compile with: /LD /GR
class B {
public:
   virtual void Test(){}
};
class D : public B {};

void f(B* pb) {
	D* pd1 = dynamic_cast<D*>(pb);
	if (pd1) {
		printf("dynamic_cast ok\n");
	}
	D* pd2 = static_cast<D*>(pb);
	if (pd2) {
		printf("static_cast ok\n");
	}
}

int main()
{
	D d;
	f(&d); //都打印了

	B b;
	f(&b); //只打印了static_cast ok
}
结论:若函数void f(B* pb)总的pb实际传入D的指针,那么都转换成功;

     若传入的实际值为B的指针,那么dynamic_cast将转换失败;而static_cast转换成功,
     所以此时static_cast可能是灾难性的。例如,调用D类的成员而不是B类的成员的函数可能会导致
     访问冲突。

?

(b) 常常用于数值数据类型转换(如枚举与整数整数与实型整形与字符型等);

//双精度转整形;
double f = 100.2f;
int a = (int)f;//c风格
int b = static_cast<int>(f);//c++风格


char c = 10;
int d = static_cast<int>(c);
//语法上没有问题,但是存在读写d后24位的可能,所以是不安全的;

????????static_cast操作符可以显式地将整型值转换为枚举类型。如果整型的值不在枚举值的范围内,则生成的枚举值未定义。

(c) void *与其他类型指针的转换

void *: 无类型指针,可以指向任何指针类型;

int a = 10;
int *pa = &a;
void *q = static_cast<void *>(pa);//不加static_cast也可以

//int *pb = q;//错误,void *类型的值不能用于初始化int *类型的实体;
int *pb = static_cast<int *>(q);//ok
//注:int *->void *       void *->int *一般没问题, 最好不要转成其他的;

static_cast操作符将空指针值转换为目标类型的空指针值。?

int *pb =  static_cast<int *>(nullptr);
double *pd = static_cast<double *>(nullptr);

?

(d) 一般不能用于指针类型间的转换(如int *转float *, float *转double *)

double d = 100.3f;
double *pd = &d;

//int *pi = static_cast<int *>(pd);//错误,类型转换无效
//float *pf = static_cast<float *>(pd);//错误,类型转换无效

?

(f) 子类(派生类)转父类(基类)

注:这里是之类和父类,而不是子类指针和父类指针;

class A {};
class B : public A {};

B b;
A a = static_cast<A>(b);//子类转父类
//B b1 = static_cast<B>(a);//错误,不支持

?

2.?dynamic_cast < type-id > ( expression )? ?

type-id必须是指向前面定义的类类型的指针或引用,或者是“指向void的指针”。

(a)如果type-id是指针,则expression 的类型必须是指针;如果type-id是引用,则expression 的类型必须是左值。??

(b)如果type-id是指向明确可访问的直接或间接基类的指针,则结果是指向type-id类型的唯一子对象的指针。例如:

// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
   C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct(直接) base class
                                   // pc points to C subobject of pd
   B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect(间接) base class
                                   // pb points to B subobject of pd
}

(c) 如果type-id为void*,则进行运行时检查以确定表达式的实际类型。结果是一个指向由表达式所指向的完整对象的指针。例如:

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
   A* pa = new A;
   B* pb = new B;
   void* pv = dynamic_cast<void*>(pa);
   // pv now points to an object of type A

   pv = dynamic_cast<void*>(pb);
   // pv now points to an object of type B
}

(d) 如果type-id不是void*,将进行运行时检查,以确定表达式所指向的对象是否可以转换为type-id所指向的类型。?

(e) 如果表达式的类型是type-id类型的基类,则会进行运行时检查,以查看表达式是否实际指向type-id类型的完整对象。如果为真,结果是指向type-id类型的完整对象的指针。例如:

// dynamic_cast_3.cpp
// compile with: /c /GR
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
   B* pb = new D;   // unclear but ok
   B* pb2 = new B;

   //这种类型转换称为"向下转换",因为它将指针向下移动到类层次结构中,从给定类移动到它派生的类;
   D* pd = dynamic_cast<D*>(pb);   // 成功: pb actually points to a D
   D* pd2 = dynamic_cast<D*>(pb2);   //失败 pb2 points to a B not a D
}

(f)?多重继承时产生的模棱两可例子:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A {virtual void f();};
class D : public B, public C {virtual void f();};

void f() {
   D* pd = new D;
   A* pa = dynamic_cast<A*>(pd);   //报错,不明确的转换在运行时失败,pa指向B呢还是C?
   B* pb = dynamic_cast<B*>(pd);   //ok, 指向pb->f后结果: D->f
   A* pa2 = dynamic_cast<A*>(pb);   // ok: unambiguous    D->f
}

?(g) 显示重复基类的类层次结构

// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
   E* pe = dynamic_cast<E*>(pd); //E->f
   B* pb = pe;   // E->f
   A* pa = pb;   // E->f
}

int main()
{
	E e;
	f(&e);
	
	return 0;
}

3.?const_cast <type-id> (expression)

去除类的const,volatile和_unaligned;

编译时就会进行类型转换;

指向任何对象类型或数据成员的指针都可以显示转换成去除const,volatile和unaligned限定符外完全相同的类型;

// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;
class CCTest {
public:
   void setNumber( int );
   void printNumber() const;
private:
   int number;
};

void CCTest::setNumber( int num ) { number = num; }

void CCTest::printNumber() const {
   cout << "\nBefore: " << number; //8
   const_cast< CCTest * >( this )->number--;
   cout << "\nAfter: " << number;  //7
}

int main() {
   CCTest X;
   X.setNumber( 8 );
   X.printNumber();
}

?只能用于指针或引用的转换!?

const int a = 1;
int a1 = const_cast<int>(a);//error  
const int a = 10;
const int *pa = &a;
int *ppa = const_cast<int *>(pa);
if (ppa)
	*ppa = 200;//语法上没错,但是写值行为是属于一种未定义行为,不要这么做;
cout << *ppa << endl;//200

4.reinterpret_cast < type-id > ( expression )

允许任何指针转换为任何其他指针类型。还允许将任何整型转换为任何指针类型,反之亦然。

int a = 10;
int *p = &a;
int *pa = reinterpret_cast<int *>(&a);

char *pc = reinterpret_cast<char *>(pa);//语法正确,但是值和范围变了

void *pv = reinterpret_cast<void *>(p);
int *ppa = reinterpret_cast<int *>(pv);

reinterpret_cast操作符可用于char*到int*或One_class*到Unrelated_class*等本质上不安全的转换。

reinterpret_cast操作符不能强制转换const、volatile或unaligned属性。

reinterpret_cast转换安全性差,但是功能很强大;只要正确转换,其实很好用;

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-03 09:21:38  更:2022-05-03 09:21:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 22:54:15-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码