1、回顾C的强制转换
大家都知道,在编译C语言中的强制转换时,编译器不会检查转换是否成功,都会编译正确。
比如:
#include "stdio.h"
struct Position
{
int x;
int y;
};
int main()
{
int i;
struct Position *p;
i=0x123456;
p=(struct Position *)i;
printf("px=%d,py=%d\n",p->x,p->y);
}
输出结果如下图所示:
从上图可以看到,只有当运行代码时,才会出现段错误问题。
当C代码上千行时,若出现这种问题,是非常难找的。
2.C++的新型类型转换
所以在C++中,便引入了4种强制类型转换
2.1 static_cast(静态类型转换)
用于基本数据类型以及对象之间的转换(char,int,const int等)
不能用于基本数据类型指针之间的转换(char *,int *等)
用于有继承关系类对象指针之间的转换
用于类指针之间的转换
示例-基本数据:
int i = 0x45;
char c = 'c';
c = static_cast<char>(i);
//char* pc = static_cast<char*>(&i); //此行错误,不能用于基本指针之间转换
示例-基本数据与对象转换:
class Test{
public:
explicit Test(int i) //只能显示调用
{
cout<<i<<endl;
}
};
int main()
{
Test t = static_cast<Test>(3.55); //等价于 : Test t(3);
}
示例-有继承关系的类对象指针转换:
class Parent
{
public:
int mm;
Parent(int i)
{
mm=i;
cout<<"Parent:"<<i<<endl;
}
};
class Child : public Parent
{
public:
int mval;
Child(int i):Parent(i)
{
mval=i;
cout<<"Child:"<<i<<endl;
}
};
int main()
{
Parent *p =new Parent(3); //会调用父类构造函数
Child *c = static_cast <Child *> (p) ; //并不会调用子类构造函数,此时的mval成员为随机值
c->mval=100;
cout<<"mval:"<<c->mval<<endl;
运行打印:
Parent:3
mval:100
mm:3
mm:100
2.2 const_cast(去常类型转换)
常用于去除const类对象的只读属性
且强制转换的类型必须是指针*或引用&
示例1:
const int x =1; //const:定义一个常量x
const int& j =2; //const引用:定义一个只读变量j
int& p1= const_cast<int&>(x); //强制转换int &
int *p2 = const_cast<int*>(&j); //强制转换int*
//int p3 = const_cast<int>(j); //此行错误,不能转换普通数据型
p1=3;
*p2=4;
printf("x=%d, j=%d\n",x,j);
printf("p1=%d *p2=%d\n",p1,*p2);
输出结果:
x=1 j=4
p1=3 *p2=4
从输出结果,可以看出修改p1,p2,只有j内容变换了,是因为变量j用const引用定义的,所以是个只读变量.
示例2-去除const类对象的只读属性
class Test
{
public:
int mval;
Test():mval(10)
{
}
};
int main()
{
const Test n1;
//n1.mval = 100; //error,不能直接修改常量对象的成员
Test *n2 = const_cast<Test *>(&n1); //通过指针*转换
Test &n3 = const_cast<Test &>(n1); //通过引用&转换
n2->mval = 20;
cout<<n1.mval<<endl; //打印20
n3.mval = 30;
cout<<n1.mval<<endl; //打印30
}
2.3 dynamic_cast(动态类型转换)
用于有继承关系的类指针(引用)间的转换
用于有交叉关系的类指针(引用)间的转换
具有类型检查的功能,编译时会去检查使用的方法是否正确,转换是否成功只有在程序运行时才能知道
类中必须有虚函数的支持
不能用于基本数据类型指针之间的转换(char *,int *等)
-当转换为指针时:
转换成功:得到目标类型的指针
转换失败 :得到一个空指针
-当转换为引用时:
转换成功:得到目标类型的引用
转换失败 :得到一个异常操作信息
示例-通过子类指针去指向父类:
#include <iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}
virtual ~Base()
{
cout << "Base::~Base()" << endl;
}
};
class Derived : public Base
{
};
int main()
{
Base* p = new Base; //初始化父类指针
Derived* pd = dynamic_cast(p); //由于父类指针指向的是父类,没有子类虚函数表,所以转换失败
cout << "pd = " << pd << endl; //转换失败,打印 0
delete p;
p = new Derived;
pd = dynamic_cast(p); //由于父类指针指向的是子类,所以有子类虚函数表
cout <<"pd = " << pd <
delete p;
return 0;
}
示例-通过多重继承下的类指针转换:
class BaseA
{
public:
virtual void funcA()
{
cout<<"BaseA: funcA()"<<endl;
}
};
class BaseB
{
public:
virtual void funcB()
{
cout<<"BaseB: funcB()"<<endl;
}
};
class Derived : public BaseA,public BaseB
{
};
int main()
{
Derived d;
BaseA *pa=&d;
pa->funcA(); //打印 BaseA: funcA()
/*通过强制转换执行*/
BaseB *pb=(BaseB *)pa;
pb->funcB(); //还是打印 BaseA: funcA(), 因为pb还是指向pa,执行的还是pa的虚函数表
/*通过dynamic_cast执行*/
pb = dynamic_cast<BaseB *>(pa);
pb->funcB(); //打印 BaseB: funcB()
//编译器会去检测pa所在的地址,发现有多个虚函数表,然后根据 <BaseB *>来修正指针pb
return 0;
}
2.4 reinterpret_ cast(解读类型转换)
用于所有指针的强制转换
(解读是指:对要转换的数据进行重新的解读)
例如:
int i = 0;
char j='c';
int *p1=reinterpret_cast<int *>(&i);
char *p2=reinterpret_cast<char *>(&j);
//int p3=reinterpret_cast<int >i; //此行错误,不能转换普通数据型
以上就是关于对C++里的4种新型类型转换的详细介绍,希望对大家的学习有所帮助。
最后,如果你也想成为程序员,想要快速掌握编程,赶紧加入学习企鹅圈子!
里面有资深专业软件开发工程师,在线解答你的所有疑惑~编程语言入门“so easy”
编程学习书籍:
编程学习视频: