文章目录
前言
你知道C中的类型转化,那么C++的呢??
1、C语言中的类型转换
首先,C语言中的内置类型之间是存在等级的;
如下等级依次递减;
(1)long double
(2)double
(3)float
(4)unsigned long long
(5)long long
(6)unsigned int
(7)int
1.而高等级类型的变量给低等级变量的复制,之间存在隐式类型转化;
例如下:
int a=10;
double b= 20;
a=b;
两类型不同的变量复制,编译器首先会进行隐式类型转化,而高等级的double类型向int类型转化是可以的!!!反之若不行,则会报错;
2.而关于两个类型不同指针之间进行赋值,则通常发生强制类型转化,
例如:
double b=20;
int * p=&b;
补充关于指针的一个基本概念:
- 指针实则就是一个地址;
- 在32位系统下,任意类型指针的大小均为4字节,那么不同类型体现在什么地方呢???
(不同类型体现在对该指针解引用时(即访问这个指针指向空间的内容时),从这个地址向后访问多少个字节;)
此情况就会报错,在于&b的类型为double*,也就意味着岂会从起始地址向后访问8个字节,而int*,则只会向后访问4个字节;所以其是无法进行隐式类型转换的,而是需要强转;
改写为: int* p=(int*) &b;
其会将double* 型的变量当作 int* 类型进行处理;
(强制类型转化一般是会生成中间变量的!!!而此情况不会)
缺陷: 首先转化的可视性比较差,所有的转型形式都是以一种相同形式书写,难以追踪错误;
2、C++中的类型转化
而C++中引入了四种的强制类型转型操作符,static_cast、reinterpret_cast、const_cast、dynamic_cast;
而之所以需要四种类型转化,一方面在于:
- 部分隐式类型转换存在,存在精度的缺失,例如double类型给int类型赋值,实则是将double类型变量的int部分赋值给int类型变量,自然小数部分则会丢失;
- 再者强转类型转换所以情况易混合一起,代码不够清晰;
接下来,就为大家介绍C++引入的这四种强制类型转换操作符;
2.1、static_cast
- static_cast用于非多态类型的转换(静态转化),同时其也是支持隐式类型的转化,但不能用于两个无关类型的相互转化;
- 而对一个类来说的非多态类型可以简单的理解为,该类对象调用成员函数,无论是普通成员函数,还是虚函数,其调用都是本类的成员函数;
double b=20.123;
int a=b;//C中的隐式类型转化
int c=static_cast<int> (b);//支持
注:static_cast可用于继承体系下类层次之间的转化,向上转型是安全的(赋值兼容规则),但是向下转型是不安全的(因为其可能会访问基类不存在的成员)
2.2、reinterpret_cast
reinterpret_cast支持将一种类型转换为另外一种不同类型,其通常为操作数的位模式提供给较低层次的重新解释;
double b=10.123;
//C中的强制类型转换
int *p=(int*)&b;
//reinterpret_cast是支持强制类型转化的
//但是针对const T*类型的转化,reinterpret_cast是不支持的,而强转则可以达到~~
int* p_=reinterpret_cast<int*> (&b);
关于函数指针:
##FUNC是对一个参数为空返回值为void的函数的指针重命名
typedef void (*FUNC)();
int DoSomething(int i)
{
cout << "DoSomething::" <<i<< endl;
return 0;
}
void Test()
{
##仍能通过编译,且运行之后i打印了为一个随机数
FUNC f = reinterpret_cast<FUNC>(DoSomething);
f();
}
首先以上的代码是不可移植的,其次C++并保证所有函数指针都能一样的使用,即可能产生不确定的结果;
2.3、const_cast
const_cast最常用的用途就是删除变量的const属性;
const int a=10;
//C中强制类型转化
int* b=(int*) &a;
//C++ const_cast
int b_=const_cast<int*> (&a);
而关于const_cast的使用,其目的并不是为了让你去修改一个本身被定义为const的值,因为这样的结果是无法预期的,const_cast的目的在于修改一些指针/引用的权限, 如果我们原来无法通过这些指针/引用修改某块内存的值,那么现在就可以了!!
如下代码:
const int a=30;
const int* pa=&a;
int* b=const_cast<int*> (pa);
*b=66;
2.4、dynamic_cast
dynamic_cast主要用于将父类指针(引用)转化为子类指针(引用);
向上转型:子类的指针或引用指向父类的指针或引用;(不需要转化,符合赋值兼容规则)
向下转型:父类的指针或引用指向子类的指针或引用; (采用dynamic_cast是安全的)
首先dynamic_cast适用于继承的体系当中,且其只能用于含有虚函数的类中!!!
那么你知道为什么要有虚函数吗????
- 首先dynamic_cast,是在运行时进行转换,而运行时转换就需要只知道类对象的信息(继承关系等);
- 而其运行时在虚函数表中获取类对象信息;
- 有了虚函数,就会修改构造函数,类对象前四个字节,这个指针便指向该类对象的所有虚函数,包括父类;
- 派生类会继承基类的虚函数表,所以通过这个虚函数表,确定该类对象的父类,在转换时即可判断对象有无继承关系~~
而关于其返回值,dynamic_cast会先检查是否能转化成功,成功返回其对象地址,反之则返回0;
例如,如下代码:
一个Animal基类,有两个类,Dog类,Cat类,继承于Aniaml类;
class Animal
{
public:
void call()
{
cout << "吼叫" << endl;
}
};
class Cat : public Animal
{
public:
void call()
{
cout << "喵喵" << endl;
}
};
class Dog :public Animal
{
public:
void call()
{
cout << "汪汪" << endl;
}
};
如下函数:
void textAniamlCall_1(Animal* an)
{
//C中的强转可以实现~
Dog* dog = (Dog*)an;
dog->call();
//当时函数传参假如是一个Dog对象,此时在强转为Cat对象,其实是一种错误的操作~
Cat* cat = (Cat*)an;
cat->call();
}
此时便可使用dynamic_cast进行类型转化
(前提是将Animal类中的Call函数修改为虚函数~~
)
void textAniamlCall_1(Animal* an)
{
Dog* dog = dynamic_cast<Dog*>(an);
if(dog)
dog->call();
Cat* cat = dynamic_cast<Cat*>(an);
if(cat)
cat->call();
}
此时就能满足,无论传参Dog类对象还是Cat类对象,在dynamic_cast作用下,都可使用对应的类中的成员函数;
注意:
1.强制类型转化的本身是关闭或挂起了正常的类型检测的,所以能不用强制类型转化就不要用强制类型转化;
2.而当非强制类型转化时,应限制强制类型转化值的作用域,以减少发送错误的可能,并且强烈不建议是用强制类型转化;
2.5、explicit
explicit是避免了像单参构造函数,导致的类型转化
如下代码
class A
{
public:
A(int num):
aa(num)
{
}
int aa;
};
void textA()
{
//编译不会报错
//其实是通过10,调用对应A(int)这一单参构造函数创建了一个对象,赋值给a;
A a = 10;
}
但是在加exlicit关键字后,在VS下出现了如下报错
总结
以上便是博主总结的C/C++中的类型转化;