C语言
我们从c语言的强制类型转换(显示和隐式)开始说起:
我们先写一个例子来回顾一下我们的强制类型转换
#include<stdio.h>
#include<iostream>
using namespace std;
int main()
{
//隐式类型转换
//1.
//将一个int型的数赋给double型
int a = 10;
double b = a;
cout<<b<<endl;
//2.
//程序会变成死循环,类型提升,i和一个size_t的类型比,回类型提升为size_t
size_t i = 0;
int n = 5;
for(;i <= n;n--)
{
printf("lalala\n");
}
//显示类型装换
//将一个整型显示的转换为一个指针类型
int c = 10;
int *p = (int *)c;
cout<<c<<endl;
return 0;
}
C++
c++的强制类型转换和c语言一样分为两种:
-
隐式类型转换
-
显示类型转换
c++的强制类型转换
-
static_case:用于非多态类型的转换,不能用于两个不相关类型的转换
-
reinterpret_cast:用于一种类型转换为另一种不同的类型
-
const_cast:用于删除变量的const属性,方便赋值
-
dynamic_cast:用于讲一个父类对象的指针和引用转换成子类的对象和引用(我们之前学过,讲一个子类的对象或引用转换成一个父类的对象或引用是没有任何问题的,这是医用天然的存在,为切片,但是反之编译器会直接报错,但是使用这个模板类就可以转换) 只能用于含有虚函数的类
我们用上面的这些来写几个例子来感受一下
#include<stdio.h>
#include<iostream>
using namespace std;
typedef void (*FUNC)();
int DoSomething(int i)
{
(int)i;
printf("DoSomething !\n");
printf("%d\n",i);
return 0;
}
int main()
{
int a = 10;
double b = static_cast<double> (a);
cout<<b<<endl;
FUNC f1;
f1 = reinterpret_cast<FUNC> (DoSomething);
f1();
//这里有一个常见的面试题
//const
const int d = 0;
int *p = const_cast<int *>(&d);
*p = 20;
cout<<"*p = "<<*p<<endl;
cout<<"d = "<<d<<endl;
cout<<"p = "<<p<<endl;
cout<<"&d = "<<&d<<endl;
return 0;
}
我们将这几个数打出来看一下,我们看到明明p指向的地址就是&a,那么为什么这两个值不一样呢?
其实这是因为编译器优化的原因,当我们将变量设为const时,编译器就默认认它不会在变,将他读到寄存器里,不会再在内存里读,但是当我们将这个值改变了之后,,编译器其实是不知道
这个值已经改变了的事实,他还是打出来的是原来的值,而我们的p是直接到内存里去读的所以打出来的是改变后的值,那我们就可以用volatile关键字来保证变量内存的可见性
没加volatile之前

加了volatile之后

最后一个是最重要的一个就是dynamic_cast,这个将父类的指针或引用给子类的指针或引用
将道理将父类的指针或引用给子类这是一个不是很正确的行为,如果不用此dynamic_cast肯定是会发生错误程序崩溃的,但是反过来可以是一个切片的行为
首先在我们使用这个的时候必须要有一个虚函数
其实我们的dynamic_cast 是一个c++中的RTTI机制(运行时类型识别机制),编译器将一个类的相关信息放到一个虚表中,然后利用class来得到它的虚表指针,得到它的虚表指针,然后在进行类型的检查等动作,就是说要使用dynamic_cast行为必须要一个虚表,所以要想得到一个虚表就必须有虚函数的多态类型
对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;
对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用