{
public:
void function1()
{
cout<<" function1 of Base_1"<<endl;
}
virtual void func()
{
}
};
class Base_2
{
public:
void function2()
{
cout<<" function2 of Base_2"<<endl;
}
};
class Base_3:public Base_1, public Base_2
{
public:
void function1()
{
cout<<" function1 of Base_3"<<endl;
}
};
int main()
{
Base_3 dst;
Base_1 src;
一、static_cast 用法:static_cast < type-id > ( expression ) :将expression转换为type-id,但没有运行时类型检查来保证转换的安全性
四种转换类型中唯一一个可以用于非指针、非引用类型的转换。
//用法:1.用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换
//上行转换(把派生类的指针或引用转换成基类表示是安全的:
Base_1 src1 = static_cast<Base_1>(dst);
//下行转换(把基类指针或引用转换成派生类表示时,由于没动态类型检查,所以是不安全的
// Base_3 dst1=static_cast<Base_3>(src);//报错: 不存在用户定义的从 "Base_1" 到 "Base_3" 的适当转换
Base_3 *dst1=static_cast<Base_3*>(&src);//改成指针就可以。那么问题来了在上行转化的时候不是指针可以,下行转换就不行呢?
//解释:
//2..普通类型转换
int i=100;
void *p =(void *)i;
// int j=static_cast<int>(p)//报错:转换类型无效,意图将 void* 转换为 int
int *j=static_cast<int*>(p);
//3.把空指针转换成目标类型的空指针。
//4.把任何类型的表达式转换成void类型。
//二、dynamic_cast 用法:dynamic_cast < type-id > ( expression ) :将expression转换为type-id,Type-id必须是类的指针、类的引用或者void*。
//支持子类指针到父类指针的转换,并根据实际情况调整指针的值,和 static_cast不同,反过来就不支持,会导致编译错误
//要求:第一、必须用于类与子类之间的转换;
//第二、必须用于指针或引用类型的转换;()
//第三、下行转换时要求基类必须有虚函数(基类中包含至少一个虚函数)。
Base_1 src_1;
Base_3 *dst2 = dynamic_cast<Base_3*>(&src_1);//如果Base_1中没有虚函数则报错: 运行时 dynamic_cast 的操作数必须包含多态类类型
dst2->function2();
//将父类经过dynamic_cast转成子类的指针竟然是空指针!这正是dynamic_cast提升安全性的功能,dynamic_cast可以识别出不安全的下行转换,但并不抛出异常,而是将转换的结果设置成null(空指针)。
getchar();
return 0;
}
//以下为转载
3. const_cast<type-id>(expression)
编译器在编译期处理
去掉类型中的常量,除了const 或不稳定的变址数,type-id和expression必须是相同的类型。
表达式const_cast<type-id>(expression)被用于从一个类中去除以下这些属性:const, volatile, 和 __unaligned。
- class A { ... };
- void f()
- {
- const A *pa = new A; <span style="color:#009900;">// const对象 </span>
- A *pb; <span style="color:#009900;">// 非const对象</span>
- pb = pa; <span style="color:#009900;">// 出错,不能将const对象指针赋值给非const对象</span>
- pb = const_cast<A*>(pa); <span style="color:#009900;">// 现在OK了</span>
- ...
- }
对于本身定义时为const的类型,即使你去掉const性,在你操作这片内容时候也要小心,只能r不能w操作,否则还是会出错:
- const char* p = "123";
- char* c = const_cast<char*>(p);
- c[0] = 1; <span style="color:#009900;">//表面上通过编译去掉了const性,但是操作其地址时系统依然不允许这么做。</span>
const_cast操作不能在不同的种类间转换。相反,它仅仅把一个它作用的表达式转换成常量。它可以使一个本来不是const类型的数据转换成const类型的,或者把const属性去掉。尽量不要使用const_cast,如果发现调用自己的函数,竟然使用了const_cast,那就赶紧打住,重新考虑一下设计吧。
去除“指针”或“引用”的const、volatile、_unaligned性。很多人都认为用这个运算符就可以让const这么“固若金汤”的东西“形同虚设”,实则不然。本质上它能做到也就是仅仅为你剥去一层虚假的外壳。如果“被指向”或“被引用”的东西本身就是const的,那么任凭你费多大力气都是徒劳的。一般它都是在这样的一套逻辑中:
- int a=34;
- const int * pcint=&a;
- int *pint=const_cast<int*>(pcint);
- *pint=0;
这样就修改了本来是const的指针(该指针要求不能修改它指向的东东),这里如果改为const int a=34;那么虽然编译依然能通过,运行依然OK,但是实际上当你用*pint来修改时,你会得到修改后的值为:a依然为34;而*pint确实为0了,但有趣的是此时pint=&a依然成立,虽然pint指向a,但是取出它的值却不等于a了。至此,希望大家今后不要再误用const_cast了。
4. reinterpret_cast<type-id>(expression)--重解释转换
编译器在编译期处理
任何指针都可以转换成其它类型的指针,type-id必须是一个指针、引用、算术类型、指向函数的指针或指向一个类成员的指针。
表达式reinterpret_cast<type-id>(a)能够用于诸如char* 到 int*,或者One_class* 到 Unrelated_class*等类似这样的转换,因此可能是不安全的。用于对指针的重新包装,也就是指针类别之间的转化。除此之外还可以用于指针类型与unsigned int类型之间的转化。
- class A { ... };
- class B { ... };
- void f()
- {
- A* pa = new A;
- void* pv = reinterpret_cast<B*>(pa);
- // pv 现在指向了一个类型为B的对象,这可能是不安全的
- ...
- }
使用reinterpret_cast 的场合不多,仅在非常必要的情形下,其他类型的强制转换不能满足要求时才使用。
这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现,举个例子:
class A {};
class B {};
A * a = new A;
B * b = reinterpret_cast<B*>(a);// 正确
更厉害的是,reinterpret_cast可以把整型数转换成地址(指针),这种转换在系统底层的操作,有极强的平台依赖性,移植性差。它同样要求new_type是指针或引用,下面的例子是通不过编译的。
double a = 2000.3;
short b;
b = reinterpret_cast<short> (a); // 编译错误
类型转换符相互比较
1. static_cast vs reinterpret_cast
reinterpret_cast是为了映射到一个完全不同类型的意思,这个关键词在我们需要把类型映射回原有类型时用到它。我们映射到的类型仅仅是为了故弄玄虚和其他目的,这是所有映射中最危险的(这句话是C++编程思想中的原话)。
static_cast 和 reinterpret_cast 操作符修改了操作数类型,它们不是互逆的。
static_cast 在编译时使用类型信息执行转换,在转换执行必要的检测(诸如指针越界计算, 类型检查). 其操作数相对是安全的。
另一方面,reinterpret_cast是C++里的强制类型转换符,操作符修改了操作数类型,但仅仅是重新解释了给出的对象的比特模型而没有进行二进制转换。
例子如下:
- int n=9;
- double d=static_cast < double > (n);
上面的例子中,我们将一个变量从 int 转换到 double。这些类型的二进制表达式是不同的。 要将整数 9 转换到双精度整数9,static_cast 需要正确地为双精度整数 d 补足比特位。其结果为 9.0。
而reinterpret_cast 的行为却不同:
- int n=9;
- double d=reinterpret_cast<double & > (n);
这次, 结果有所不同。在进行计算以后, d 包含无用值。这是因为 reinterpret_cast 仅仅是复制 n 的比特位到 d,没有进行必要的分析。因此,你需要谨慎使reinterpret_cast。
reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。
例如,假设你有一个函数指针数组:
- typedefvoid(*FuncPtr)();// FuncPtr is一个指向函数的指针,该函数没有参数,返回值类型为void
- FuncPtrfuncPtrArray[10];// funcPtrArray是一个能容纳10个FuncPtrs指针的数组
你不能不经过类型转换而直接去做,因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型,而doSomething函数返回值是int类型。
funcPtrArray[0] = &doSomething;// 错误!类型不匹配
reinterpret_cast可以让你迫使编译器以你的方法去看待它们:
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething);
转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果。
2. dynamic_cast vs static_cast
class B { ... };
class D : public B { ... };
void f(B* pb)
{
D* pd1 = dynamic_cast<D*>(pb);
D* pd2 = static_cast<D*>(pb);
}
如果pb确实是指向D类型对象,则pd1和pd2将拥有同样的值。即使pd为0,它们的值也相同。如果pb执行B类型对象而不是D类型,则dynamic_cast返回0.可是static_cast依赖编程者安全断言--pb指向D类型对象并简单地返回给定的D对象指针。