c++之强制类型转换

c++之强制类型转换,第1张

目录

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 ( 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(pb);   // Not safe, D can have fields
                                   // and methods that are not in B.

   B* pb2 = static_cast(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(pb);
	if (pd1) {
		printf("dynamic_cast ok\n");
	}
	D* pd2 = static_cast(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(f);//c++风格


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

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

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

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

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

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

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

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

 

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

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

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

 

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

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

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

B b;
A a = static_cast(b);//子类转父类
//B b1 = static_cast(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(pd);   // ok: C is a direct(直接) base class
                                   // pc points to C subobject of pd
   B* pb = dynamic_cast(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(pa);
   // pv now points to an object of type A

   pv = dynamic_cast(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(pb);   // 成功: pb actually points to a D
   D* pd2 = dynamic_cast(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(pd);   //报错,不明确的转换在运行时失败,pa指向B呢还是C?
   B* pb = dynamic_cast(pd);   //ok, 指向pb->f后结果: D->f
   A* pa2 = dynamic_cast(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(pd); //E->f
   B* pb = pe;   // E->f
   A* pa = pb;   // E->f
}

int main()
{
	E e;
	f(&e);
	
	return 0;
}
3. const_cast (expression)

去除类的const,volatile和_unaligned;

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

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

// expre_const_cast_Operator.cpp
// compile with: /EHsc
#include 

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(a);//error  
const int a = 10;
const int *pa = &a;
int *ppa = const_cast(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(&a);

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

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

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

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

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

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/789169.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-05
下一篇 2022-05-05

发表评论

登录后才能评论

评论列表(0条)

保存