前言
在深入理解C语言中的类型转换一文中对C语言中出现的隐式转换和显示转换进行了总结,在那篇文章中所提到的所有类型转换都适用于C++语言,本文将特别关注C++语言中的类型转换,主要概括出C++不同于C语言的知识点。
隐式转换
C语言中的隐式转换
主要参考前言中提到的那篇文章,在此不再重复叙述。
类类型转换
作为一门面向对象的编程语言,C++在C语言基础上从程序语言层次上支持了类及其一系列相关特性,例如继承、虚函数、多态等。每个类都有构造函数,当构造函数只接受一个参数时,通常将其称为转换构造函数,此外,也可以用类型转换操作符将类类型转换为其他类型。
#include <iostream>
using namespace std;
class SmallInt {
public:
// 转换构造函数,int转为SmallInt
SmallInt(int i) : val(i) {}
// 类型转换操作符,SmallInt转为int
operator int() const {return val;}
private:
int val;
};
int main()
{
// 隐式转换,从int到SmallInt
SmallInt si = 1;
// 隐式转换,从SmallInt到int
int i = si;
cout << i << endl;
return 0;
}
派生类到基类的转换
可以讲基类的指针或者引用绑定到派生类的对象上,这是有编译器自动完成的转换,所以称为隐式转换。
class A {
};
class B : public A {
};
int main()
{
A* a = new B();
return 0;
}
显示转换
在C++中,对于显示转换不再使用像C语言那样的简单粗暴的转换方式,而是提供了四个cast,分别是static_cast,dynamic_cast,const_cast和reinterpret_cast。
static_cast
static_cast主要解决以下几种情况中编译器无法隐式完成的转换。
- void* 指针转为其他指针;
- 对于任意两种内置类型间的转换,编译器本身可以自动完成,但是会发出告警,static_cast会清除这些告警。
- 对于基类向派生类指针的转换来说,当基类中无virtual函数时,用static_cast是可以的;如果有virtual函数时,可以让编译通过,但是由于static_cast缺少运行时检查,会不安全。
class A {
};
class B : public A {
};
class C {
protected:
virtual void test () {}
};
class D : public C{
void test() {}
};
int main()
{
int i = 1;
double d = 2.0;
// 成功
d += static_cast<int>(i);
// 隐式转换
void* pv = &i;
// 成功
int* pi = static_cast<int*>(pv);
// 失败
double* pd = static_cast<double*>(pi);
const char* file = "abc.txt";
// 失败
char* myfile = static_cast<char*>(file);
A* a = new B();
// 成功
B* b = static_cast<B*>(a);
C* c = new D();
// 编译通过,但是运行时不安全
D* dc = static_cast<D*>(c);
return 0;
}
dynamic_cast
dynamic_cast用于解决含有多态类型(virtual函数)的基类向派生类的转换。
class A {
};
class B : public A {
};
class C {
protected:
virtual void test () {}
};
class D : public C{
void test() {}
};
int main()
{
int i = 1;
double d = 2.0;
// 错误
d += dynamic_cast<int>(i);
// 隐式转换
void* pv = &i;
// 错误
int* pi = dynamic_cast<int*>(pv);
// 错误
double* pd = dynamic_cast<double*>(pi);
const char* file = "abc.txt";
// 错误
char* myfile = dynamic_cast<char*>(file);
A* a = new B();
// 错误, dynamic_cast的操作数必须包含多态类型
B* b = dynamic_cast<B*>(a);
C* c = new D();
// 正确
D* dc = dynamic_cast<D*>(c);
return 0;
}
const_cast
const_cast用来解决const指针向非const类型的转换。
class A {
};
class B : public A {
};
class C {
protected:
virtual void test () {}
};
class D : public C{
void test() {}
};
int main()
{
int i = 1;
double d = 2.0;
// 错误
d += const_cast<int>(i);
// 隐式转换
void* pv = &i;
// 错误
int* pi = const_cast<int*>(pv);
// 错误
double* pd = const_cast<double*>(pi);
const char* file = "abc.txt";
// 正确
char* myfile = const_cast<char*>(file);
A* a = new B();
// 错误
B* b = const_cast<B*>(a);
C* c = new D();
// 错误
D* dc = const_cast<D*>(c);
return 0;
}
reinterpret_cast
除了const无法转换外,reinterpret_cast可以用来完成其他任意类型的转换,但是其非常不安全,类似于C语言中的显示转换方式。
class A {
};
class B : public A {
};
class C {
protected:
virtual void test () {}
};
class D : public C{
void test() {}
};
int main()
{
int i = 1;
double d = 2.0;
// 正确
d += reinterpret_cast<int>(i);
// 隐式转换
void* pv = &i;
// 正确
int* pi = reinterpret_cast<int*>(pv);
// 正确
double* pd = reinterpret_cast<double*>(pi);
const char* file = "abc.txt";
// 错误
// char* myfile = reinterpret_cast<char*>(file);
A* a = new B();
// 正确
B* b = reinterpret_cast<B*>(a);
C* c = new D();
// 正确
D* dc = reinterpret_cast<D*>(c);
return 0;
}