还记得初学c++时觉得为啥要搞四种类型转换 好麻烦 为什么不能像c语言搞成一种(T)的方式来进行所有的类型转换呢?(如下代码) 当年很菜的我对于这个问题百思不得其解 现在这里统一对这四种类型转换做一个总结
int i=1;
int *p=(int*)i;
那么问题来了 为啥C语言一种方式就可以涵盖所有类型转换呢?并且C标准更新也没有像c++一样加上其他的类型转换呢?最大的原因还是由于c++是可以面向对象编程的语言 而c是面向过程的语言 也就是说c不会有各种奇奇怪怪的东西 比如封装继承多态, 没有了这些面向对象的东西也就意味着他压根不需要其他类型转换的方式(const_cast除外 这个东西纯粹是为了一些莫名其妙的目的而推出来的 理论上来说就不应该存在定义为const 然后又要修改的情况 除非你一开始就没想好)
那么问题来了 形如上述C语言的类型转换的方式在面向对象编程中有啥缺点呢 我们来看一个最简单的例子
class A {
public:
int m_a{1997};
};
class D :public A
{
public:
int m_d;
}
int main()
{
A* a = new A;
D* d = (D*)a;
std::cout<<d->m_d;
}
上面这段代码 轻则导致系统运行出问题 重则直接程序崩溃 这个时候抖机灵的小伙伴又要说了 那我每次强转的时候都人工保证他100%安全不就好了嘛?现在 试想一下 你在完成一个几十万行代码几百万行代码的超大工程 并且类的继承体系及其复杂 你只负责了自己的一小部分 然后有一天系统突然崩溃了 原因就是因为团队里有个没完全搞懂类继承体系的小白乱用强转导致的 那你怎么办 你排查这个问题需要耗费的时间是多少?
所以这个时候 c++程序员就迫切的希望有一种更加完善的更加牛逼的类型转换机制来供大家使用
申明:如果你的项目体量并不大 十几个类几万行代码就可以搞定而且你对你的代码拿捏的住 各种安全你也不用考虑的话 那么你完全可以不使用c++里的类型转换
const_cast
这个强制类型转换和面向对象没有半毛钱关系,所以这里先讲这个东西,顾名思义就是可以运行你将常量给转换为普通数据类型 或者将普通数据类型给加上常量的限制 看以下代码
不要尝试去修改常量区的数据哦 否则有你好果子吃
static_cast
什么叫做static?就是静态的 也就是意味着他发生在编译阶段 你可以把他当做所有的隐式转换和不安全的向下转型!
所有的隐式类型转换指的是 如下代码所写 所有的隐式类型转换都可以使用static_cast
//float f=3.14f;
//double d=f;
float f = 3.14f;
double d = static_cast<double>(f);
下面这段不允许发生隐式类型转换的场景 使用static_cast也不会允许你转型的
向下类型转换指的是
class A {
public:
virtual void test()
{
}
int m_a{1997};
};
class D :public A
{
public:
int m_d;
};
class E :public A
{
public:
int m_e;
};
int main()
{
A a;
//报错 如果不使用static_cast编译器不会给你自动向下转型 因为这是不安全的
//D* d=&d;
//下面这句代码是正确的 相当于你手动告诉编译器 我知道我在干什么 我就是要向下转型
D* d = static_cast<D*>(&a);
}
reinterpret_cast
顾名思义 reinterpret 也就是重新解释 这是啥意思呢 他可以支持所有的类型转换 任意类型转任意类型且不会做任何安全检查 看如下这段代码
class A {
public:
int m_a{1997};
};
class B
{
public:
int m_b{ 1998 };
};
class C :public A, public B
{
};
int main()
{
C c;
std::cout<<reinterpret_cast<B*>(&c)->m_b<<std::endl;
std::cout << static_cast<B*>(&c)->m_b << std::endl;
}
输出结果令人惊讶
这是为啥呢 因为reinterpert_cast只是重新解释了这个&c 所以他默认是去第一个四字节访问数据 这也就导致了输出1997 而static_cast向上转型的时候默认把指针向后移了四个字节 所以输出是正确的 输出了1998
看下面这段代码就懂了
这就叫重新解释!是从二进制比特位进行的重新解释 与原来内存里保存的东西不会有任何区别 所以他是非常危险的
dynamic_cast
dynamic就是动态的意思 那么也就是说是发生运行阶段的类型转换 是有可能失败的 有作用且仅在有类中有虚函数表指针的时候有作用 因为虚函数表会保存类型信息 所以在运行时才能进行动态类型转换!
必须要有虚函数表 必须要有虚函数表 必须要有虚函数表
class A {
public:
virtual void test()
{
return;
};
int m_a{1997};
};
class B:public A
{
public:
int m_b{ 1998 };
};
class C :public A
{
public:
int m_c{ 1999 };
};
int main()
{
A* a = new B;
if (dynamic_cast<B*>(a) == nullptr)
{
std::cout << "dynamic_cast<B*> failure" << std::endl;
}
if (dynamic_cast<C*>(a) == nullptr)
{
std::cout << "dynamic_cast<C*> failure" << std::endl;
}
}
运行结果如下
总结
好了 如果你对你的代码有自信 完全可以不使用c++的类型转换 c++的类型转换只是在c语言风格的类型转换上分的更加细致了 给了更大程序的控制权限而已