1.static_cast<> ()
static_cast<> 属于编译时类型检查 可以将子类对象强制转换成父类对象,还有系统内置类型的强制类型转换
class Base
{
public:
void show()
{
cout << "Base 的show函数调用";
cout << endl;
}
};
class Son :public Base
{
public:
void show()
{
cout << "Son 的show函数调用";
cout << endl;
}
};
上面的Son继承Base类,首先来看一下将子类对象转换成父类对象
Son s1;
Base b1 = static_cast<Base>(s1);//将s1转换成base对象(子类转父类)
b1.show();//此处调用的是Base类的show函数
s1.show();
注意:这四个强制类型转换在使用的时候都需要加上();此处将b1强制类型转换成Base类对象(子类转父类),static_cast<>()只能将子类对象转化成父类对象,将父类对象转换成子类对象会报错。
static_cast<>()将void*与其他类型指针之间的转换:
int i = 10;
int* p = &i;
void* v = static_cast<void*>(p);//int 转void*
int* m = static_cast<int*>(v);//void*转int
此处说明一下void*类型的指针是无类型的指针,就是它可以指向任何类型的指针,如果将其他的指针转换成void*类型的指针,在使用的时候要记得转回去,不然会出错
static_cast<>()最常用于内置类型之间的转换
int a = 100;
float b = static_cast<float>(a);//int 转float
double db = static_cast<double>(a);//int 转double
char ch = static_cast<char>(a);//int 转char
cout <<a<< endl;
cout << b << endl;
cout << db << endl;
cout << ch << endl;
内置类型之间的相互转换都是可行的,这种写法和c风格强制类型转换基本一致

下面来谈谈static_cast<>()不可以转换的情况:

不能用于内置类型的指针的转换,int* ,double*,float*,等
2.const_cast<>()
2.const_cast<>()属于编译时类型检查 ,能够去掉表达式的常量属性;能够取消指针或者引用的const属性,使其可以被修改
const int m = 100;//现在m是不可修改的
int arc = const_cast<int>(m);//错误的写法
当我们这样写是错误的,系统会报错

所以这里只能传指针或者引用 ,下面开始测试:
const int m = 100;//现在m是不可修改的
const int* p = &m;
int *p1 = const_cast<int*>(p);
*p1 = 10;
cout << *p1 << endl;
cout << *p<< endl;
cout << m<<endl;
我们将指针p转换成可以修改的p1,修改p1的值后,p的值也会随之改变,m的值依旧不变

注意:如果原来是一个常量,你通过const_cast<>()将其变为可修改的并且改变其值,这是一种未定义的行为,容易带来风险,最好不要这样写。
3.reinterpret_cast<>()
属于编译时类型检查;可以把一些不相干的类型之间实现强制类型转换,转换比较随意
int i = 1;
int* p1 = reinterpret_cast<int*>(&i);//将地址转换成int*
char* p2 = reinterpret_cast<char*>(&i);
对于第二个用法,需要注意,这个地址里面存的是int,却把他转成了字符型指针,虽然编译器没有报错,但是实际在使用过程中不建议这样写。
可以进行两个无关自定义类型指针之间的转换:
class A{};
class B{};
先定义两个无关的类
A *a=new A;
B *b = reinterpret_cast<B*>(a);

可以看到转换成功,但是在实际应用中不建议这样乱转,不仅没有意义,而且会导致程序出错
4.dynamic_cast<>()
dynamic_cast<>()运行时类型检查;将父类指针转换成子类指针,通过父类指针创建的对象只能调用重写父类的那个虚函数,不能调用自己的成员函数,因此需要通过dynamic_cast<>()来解决这个问题
class Human
{
public:
virtual void eat() = 0;
void sleep(){}
virtual ~Human()
{
}
};
class Woman:public Human
{
public:
void eat()
{
cout << "吃饭" << endl;
}
void func()
{
cout << "调用woman的fun()" << endl;
}
};
class Man :public Human
{
public:
void eat()
{
cout << "吃肉" << endl;
}
void fun(){
cout << "fun()函数调用" << endl;
}
};
先写一个父类Human ,其内有一个纯虚函数 virtual void eat()=0;这个函数分别在两个子类里面都进行了重写,子类里面也有自己的成员函数func(),fun;注意父类的析构函数必须写成虚函数,否则会出现父类指针无法释放子类对象的情况。
Human* hum = new Man;
hum->eat();
cout << typeid(hum).name() << endl;//返会类型
Man* m = dynamic_cast<Man*>(hum);//将父类指针转换成子类指针,转换失败则返回空指针
m->fun();//转换之后就可以调用子类的成员函数
cout << typeid(m).name() << endl;
此处结合运行时类型识别 typeid() 一起说明,首先通过父类指针创建一个子类对象。此处hum->eat()会调用Man的eat函数,typeid里面传入的就是当前想要识别的对象指针,再通过调用其成员函数就会得到相应的类型名称,在通过dynamic_cast<>() 将父类指针转换成子类指针就可以调用子类的成员函数,dynamic_cast<>()也可以将父类指针转换成子类对象,但是这个不安全

dynamic_cast<>()如果转换失败会返回一个bad_cast
Human& q = *hum;
try
{
Man ma = dynamic_cast<Man&>(q);
cout << "父类引用转换成子类引用" << endl;
}
catch (bad_cast)//如果转换失败返回bad_cast
{
cout << "转换失败" << endl;
}
const type_info& tp = typeid(*hum);//type_inf返回常量引用
cout << tp.name() << endl;
我们用try catch机制捕捉一下试试看

此处是转换成功的,没有输出“转换失败”,typeinfo 返回常量引用,可以通过它的name()成员函数返回类型。下面举一个转换失败的例子
class A {
public:
virtual void func() { cout << "Class A" << endl; }
private:
int m_a;
};
class B : public A {
public:
virtual void func(){ cout << "Class B" << endl; }
private:
int m_b;
};
注意此处父类中没有纯虚函数,因此父类是可以创建对象的
A* pa = new A();
B* pb;
pb = dynamic_cast<B*>(pa); //向下转型失败
if (pb == NULL) {
cout << "转换失败" << endl;
}
else {
cout << "转换成功" << endl;
pb->func();
}
此处会输出转换失败,对于此处有一种说法是:dynamic_cast 会在程序运行过程中遍历继承链,如果途中遇到了要转换的目标类型,那么就能够转换成功,如果直到继承链的顶点(最顶层的基类)还没有遇到要转换的目标类型,那么就转换失败,映射到此处,pa创建的A类对象就是继承链的顶部了,不能再向上遍历继承链,因此转换失败.
本文介绍了C++中的四种强制类型转换方法:static_cast用于子类转父类、内置类型转换,const_cast用于取消常量属性,reinterpret_cast用于任意类型间的转换,而dynamic_cast用于运行时类型检查,处理父类指针与子类对象的转换。

465

被折叠的 条评论
为什么被折叠?



