目录
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转换安全性差,但是功能很强大;只要正确转换,其实很好用;
?
|