C++中的类型转换
隐式转换
- 当一个值拷贝给另一个兼容类型的时候,隐式转换会自动进行,有编译器操作。
- C++面向对象的多态特性,本质就是通过父类指针实现对子类指针的封装,这其中也发生了隐式转换。除此之外,各种数值类型的转换等等,都给开发带来了不小便利。
- 隐式转换的原则:低精度 -> 高精度,子类 -> 父类
- 发生的条件:
- 混合类型的运算中
- 不同类型的赋值操作
- 参数传递
- 返回值传递
- 隐式转换的风险一般在于自定义的类构造函数中,如果类的构造函数只有一个参数,编译器会默认规定这也是一个隐式的类型转换,可能会把参数类型的数据隐式转换成这个类类型。
class Test{
public:
Test(int i) : x(i) {}
int x;
};
int main () {
Test t(10);
t = 20;//编译通过,20隐式转换为了Test(20)
}
- 另外可以用
operator Typename () const {return (Typename) xx}
将该类类型隐式转换成Typename
类型 - 在一个参数的构造函数前加上
explicit
可以禁止隐式转换
显示转换
- 类C型的显示转换,即在前面加上
(Typename)
,虽然也能满足需求,但是有风险,因为如果在指针上使用这种强制转换成其他类型的指针,编译器不会报错,但是运行的时候可能会出错。比如有两个指针分别指向A、B两个类,我把B的指针强制转换为A类型并赋给A的指针,如果我们用这个指针调用A的函数,此时编译不会报错,但是运行的时候就会崩溃
static_cast
首先是静态转化,static_cast,也是我们经常使用的类型转化,叫做静态转化的原因是它在编译时检查类型,也就是我们在写代码的时候就已经会检测类型转化是否正确了。
- 运用场景第一就是各种数值类型的转化,比如float转化成int,或者字符转化成int之类的,类似于C的隐式转化;
- 第二个就是空指针和实际类型的转化,把void指针转化成实际类型,或者反过来。
- 第三个使用场景就是类的层次之间的转化,比如子类指针转化成父类指针,或者父类到子类的转化,但是下行转化是不安全的,因为它只会检查这两个类型是不是父子类,而不会检查这个指针指向的对象是不是对的,比如我们把一个指向父类的指针,转化成子类指针,调用子类的函数,编译不会报错,但是它实际并不是子类,调用子类函数在运行时就会报错了。
dynamic_cast
- 所以也就引入了第二个类型转化,dynamic_cast,动态转化,应用场景也就是把父类指针转化为子类指针。在C++中为了实现动态多态,我们会使用一个父类指针实际指向一个子类对象,但有时候我们需要调用到子类特有的函数或者字段,这是无法通过父类指针做到了,我们就需要用动态转化把父类指针转化成子类指针,并且动态转化会在运行时检查类型,如果实际对象确实是子类,就返回子类指针,否则返回一个空指针。至于如何实现动态检查的,实际上是通过虚函数表来实现的,当父子类中存在虚函数的时候,就会有一个虚函数表,动态转化在运行时通过虚函数指针查找到虚函数表,进而确定实际对象是不是子类,这其实也是虚函数多态的实现方式。
dynamic_cast
只能用于指向类的指针和引用或者void*
,目的是确保类型转换的结果指向目标指针类型的有效完整对象dynamic_cast
可以将父类指针转换为子类的指针,如果此时父类指针确实指向的是一个子类对象,则转换成功,否则转换失败,指向null。但是要求父类必须要有虚函数,因为dynamic_cast
是使用了RTTI信息在运行时推导父类指针实际的对象
class Test {
public:
virtual void test (){
cout << "ss" << endl;
}
};
class Test2 : public Test{
};
class Test3{
public:
virtual void test() {
cout << "ss" << endl;
}
};
int main() {
Test* t1 = new Test2;
Test* t2 = new Test;
Test3* t3 = new Test3;
Test2* tt;
tt = dynamic_cast<Test2*>(t1);
cout << tt << endl;
tt = dynamic_cast<Test2*>(t2);
cout << tt << endl;
tt = dynamic_cast<Test2*>(t3);
cout << tt << endl;
}
//结果为
//00C6F820
//00000000
//00000000
//只有第一个转换成功
const_cast
- const_cast: 把const属性去掉,即将const转换为非const(也可以反过来),const_cast只能用于指针或引用.
reinterpret_cast
- 最后一个,也是最少使用的一个转化,reinterpret_cast,直接翻译过来应该是重新解释,或者重译,说明白点其实就是强制转化,把一个类型的对象重新翻译成新类型,跟C的强制转化一样,可以转化任意类型的对象,所以在使用上需要小心。