1.C语言中的类型转换
分为隐式类型转化、显示强制类型转化。
隐式类型转化用于意义相近的类型,比如int,double,short都是表示数值的类型
int i=1; double d=i; //编译、结果无问题 这里是隐式类型转换。
显示强制类型转换
显示强制类型用于意义不相近的类型,比如地址和int
int *p=&i; int address=(int) p;//使用显示强制类型转换时编译、结果才无问题。
缺陷:转换的可视性差,所有类型转换的形式都是一种相同形式,错误难以排查。
2.C++的类型转换
标准C++为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符。
static_cast reinterpret_cast const_cast dynamic_cast
2.1 static_cast
static_cast 用于非多态类型的转换(静态转换)。编译器隐式执行的任何类型转换都可以用static_cast(用于意义相近的类型,不相关的类型用会报错)
int main()
{
double d=23.14;
int a=static_cast<int>(d);
cout<<a<<endl;
return 0;
}
2.2 reinterpret_cast
不相关类型的转换
int main()
{
double d = 23.14;
int a = static_cast<int>(d);
int* p = reinterpret_cast<int*>(a);//将一个表示数值的整形变成了地址
return 0;
}
2.3 const_cast
删除变量的const属性,方便赋值。
int main()
{
const int a = 2;
int* p = const_cast<int*>(&a);//const int* 转换成了int*
*p = 3;
cout << a << endl << *p << endl;
return 0;
}
为什么我们在监视窗口确实看到了a的值被修改成了3,而最终结果仍然是2呢?
这里是编译器的一些优化,有些编译器会将const变量直接放在寄存器中,需要使用a的时候直接从寄存器拿,而调试相当于另一个进程,自然不会影响我们主进程的结果。有些编译器(VS)会将const变量声明成宏的形式,在使用的时候直接输出结果而不是变量值。
2.4 dynamic_cast
用于将一个父类对象的指针和引用转换为子类对象的指针或引用。(动态转换)
向上转型:子类对象指针/引用 转换为父类对象指针/引用 (不需要转换,赋值兼容规则,切片)
向下转型:父类对象指针/引用 转子类 (用dynamic_cast转型是安全的)
注意
dynamic_cast只能用于父类中含有虚函数的类。
dynamic_cast会先检查是否能转换成功,能成功就转换,不能返回0
class a
{
public:
virtual void f(){}
public:
int _a = 0;
};
class b : public a
{
public:
int _b = 1;
};
// a*指针pa有可能指向父类,有可能指向子类
void fun(a* pa)
{
// 如果pa是指向子类,那么可以转换,转换表达式返回正确的地址
// 如果pa是指向父类,那么不能转换,转换表达式返回nullptr
b* pb = dynamic_cast<b*>(pa); // 安全的
//b* pb = (b*)pa; // 不安全
if (pb)
{
cout << "转换成功" << endl;
pb->_a++;
pb->_b++;
cout << pb->_a << ":" << pb->_b << endl;
}
else
{
cout << "转换失败" << endl;
pa->_a++;
cout << pa->_a << endl;
}
}
int main()
{
a aa;
// 父类对象无论如何都是不允许转换成子类对象的
/*b bb = dynamic_cast<b>(aa);
b bb = (b)aa;*/
b bb;
fun(&aa);
fun(&bb);
//fun(nullptr);
return 0;
}
2.4.2 dynamic_cast的意义
如果我们仍然使用C语言中的强制类型转换,不论我传入的pa是子类指针还是父类指针,结果就会都是转换成功。并且当我传入的是父类指针时,解引用出现错误,导致程序终止。
2.4.3 dynamic_cast和强制类型转换的多继承
class A1
{
public:
virtual void f(){}
public:
int _a1 = 0;
};
class A2
{
public:
virtual void f(){}
public:
int _a2 = 0;
};
class B : public A1, public A2
{
public:
int _b = 1;
};
注意强制类型转换也会让指针偏移回去,在这里和dynamic_cast结果是一样的