在 C 语言中,类型转换的方式一般可分为隐式类型转换和显示类型转换(也称为强制类型转换)。其中隐式类型转换由编译器自动进行,不需要程序员干预。
隐式类型转换通常有两种情况:赋值转换和运算转换。
强制类型转换是程序员显式告诉编译器将一个数据类型转换为另一个数据类型的操作。语法结构如下:
c语言强制类型转换主要用于基础的数据类型间的转换,语法为:
- (type-id)expression//转换格式1
-
- type-id(expression)//转换格式2
其中type_id是目标数据类型,expression是要转换的表达式。
- float x = 10.75;
- int y = (int) x; // y的值为10
- char ch = 'A';
- int ascii = (int) ch; // ascii的值为65
const_cast是一种C++运算符,主要是用来去除复合类型中const(不变的)和volatile(不稳定的)属性(没有真正去除)。
不能对非指针和非引用的变量使用const_cast操作符去直接移除它的const、volatile和__unaligned属性。
用法:const_cast
•常量指针转化为非常量的指针,并且仍然指向原来的对象
•常量引用转化为非常量的引用,并且仍然指向原来的对象
也就是说源类型和目标类型除了const属性不同,其他地方完全相同。
const 的机制,就是在编译期间,用一个常量代替了 data。这种方式叫做常量折叠。
常量折叠与编译器的工作原理有关,是编译器的一种编译优化。在编译器进行语法分析的时候,将常量表达式计算求值,并用求得的值来替换表达式,放入常量表。所以在上面的例子中,编译器在优化的过程中,会把碰到的data(为const常量)全部以内容100替换掉,跟宏的替换有点类似。
常量折叠只对原生类型起作用,对我们自定义的类型,是不会起作用的。
- const int g = 20;
- int *h = const_cast<int*>(&g);//去掉const常量const属性
-
- const int g = 20;
- int &h = const_cast<int &>(g);//去掉const引用const属性
-
- const char *g = "hello";
- char *h = const_cast<char *>(g);//去掉const指针const属性
static_cast静态转换相当于C语言中的强制转换,但不能实现普通指针数据(空指针除外)的强制转换,一般用于父类和子类指针、引用间的相互转换。没有运行时类型检查来保证转换的安全性。
static_cast的转换格式:static_cast
1.用于类层次结构中,基类和派生类之间指针和引用的转换;
当进行上行转换,也就是把子类的指针或引用转换成父类表示,这种转换是安全的;
当进行下行转换,也就是把父类的指针或引用转换成子类表示,这种转换是不安全的,也需要程序员来保证;
- QWidget* wid = new QWidget();
- QObject* obj = static_cast<QObject*>(wid);
2.用于基本数据类型之间的转换,如把int转换成char,把int转换成enum等等,这种转换的安全性需要程序员来保证;
使用static_cast可以明确告诉编译器,这种损失精度的转换是在知情的情况下进行的,也可以让阅读程序的其他程序员明确你转换的目的不是由于疏忽。
把精度大的类型转换为精度小的类型,static_cast使用位截断进行处理。
3.把void指针转换成目标类型的指针,是及其不安全的;
4.把空指针转换成目标类型的空指针。
注:static_cast不能转换掉expression的const、volatile和__unaligned属性。
编译器隐式执行的任何类型转换都可以由static_cast来完成,比如int与float、double与char、enum与int之间的转换等。
C++中的static_cast,用于代替C中通常的转换操作。因此,被做为隐式类型转换使用。比如:
- double a = 1.999;
- int b = static_cast<double>(a); //相当于a = b ;
reinterpret_cast的转换格式:reinterpret_cast
一个指针、引用、算术类型、函数指针或者成员指针
reinterpret_cast主要有几种强制转换用途:将指针或引用转换为一个足够长度的整型、将整型转换为指针或引用类型。
允许将任何指针类型转换为其它的指针类型;听起来很强大,但是也很不靠谱。它主要用于将一种数据类型从一种类型转换为另一种类型。它可以将一个指针转换成一个整数,也可以将一个整数转换成一个指针,在实际开发中,先把一个指针转换成一个整数,在把该整数转换成原类型的指针,还可以得到原来的指针值;特别是开辟了系统全局的内存空间,需要在多个应用程序之间使用时,需要彼此共享,传递这个内存空间的指针时,就可以将指针转换成整数值,得到以后,再将整数值转换成指针,进行对应的操作。
C++中的reinterpret_cast主要是将数据从一种类型转换为另一种类型。所谓“通常为操作数的位模式提供较低层的重新解释”也就是说将数据以二进制存在形式的重新解释。比如:
- int i;
- char *p = "This is a example.";
- i = reinterpret_cast<int>(p);
- dynamic_cast<type*>(e)
-
- dynamic_cast<type&>(e)
-
- dynamic_cast<type&&>(e)
type必须是一个类类型,在第一种形式中,type必须是一个有效的指针,在第二种形式中,type必须是一个左值,在第三种形式中,type必须是一个右值。
向上转换,无论是否用dynamic_cast,C++总是能够正确识别,即将派生类的指针赋值给基类指针。
RTTI:Run Time Type Identification,即通过运行时类型识别。程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。
主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换
可以从一个虚的基类强制到一个派生类。(下行转换)
虚基类(或称抽象类)可以使用dynamic_cast,但是,非虚基类不可以。
在dynamic_cast被设计之前,C++无法实现从一个虚基类到派生类的强制转换。dynamic_cast就是为解决虚基类到派生类的转换而设计的。
qt中
函数的行为类似于标准c++ dynamic_cast(),其优点是它不需要RTTI支持,并且可以跨动态库边界工作。
在使用时有两个限制:
1# T类型必须继承自QObject。
2# 在声明时必须有Q_OBJECT宏。
qobject_cast 函数,使用语法如下 DestType* qobject_cast(QObject *p); 该函数类似于 C++中的 dynamic_cast,但执行速度比 dynamic_cast 更快,且不需要 C++的 RTTI 的支持,但 qobject_cast 仅适用于 QObject 及其派生类。
主要作用是把源类型 QObject 转换为尖括号中的目标类型 DesType(或者子类型),并 返回指向目标类型的指针,若转换失败,则返回 0。或者说源类型 QObject 属于目标 类型 DestType(或其子类型),则返回指向目标类型的指针,否则返回 0。
使用 qobject_cast 的条件:目标类型 DestType 必须继承(直接或间接)自 QObject,并 使用 Q_OBJECT 宏。
适用于多个对象连接到同一个槽函数。可以简化信号槽的编写。
- connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::changeBtn);
- connect(ui->pushButton_2,&QPushButton::clicked,this,&MainWindow::changeBtn);
- void MainWindow::changeBtn()
- {
- QPushButton* pp = qobject_cast<QPushButton*>(sender());
- if(pp == ui->pushButton){
- qDebug()<<"success";
- }else if(pp == ui->pushButton_2){
- qDebug()<<"success_2";
- }
- }
sender()函数作用
当某一个Object emit一个signal的时候,它就是一个sender,系统会记录下当前是谁emit出这个signal的,所以你在对应的slot里就可以通过 sender()得到当前是谁invoke了你的slot,对应的是QObject->d->sender.
1、使用sender()方法获取信号的发送对象,前提是槽函数是被信号触发的,而非自己调用,否则返回空(nullptr),所以我们在使用的时候最好加个非空判断;
2、通过此方法获取的对象指针仅在槽函数执行的期间有效;
3、如果在此期间,信号发送对象被销毁,或者信号与槽函数已经断开,此对象指针将无效;
4、此方法虽然违背了面向对象的模块化原则,但是当多个信号连接同一个槽函数的时候,可以通过此方法获取到发送信号的对象,根据这个对象来判断当前是哪个信号触发的槽函数,当我们多个信号绑定一个槽函数的时候,一般是需要根据信号的不同来做不同的操作,所以这里可以获取到实际发生信号的对象,那我们就知道是哪个信号,然后就可以去处理了。
5、当我们使用 Qt::DirectConnection 类型作为信号槽的连接方式,且槽函数调用的线程不同于信号发送对象的线程,这个时候sender()方法返回的QObject对象指针是无效的,这种场景是不可以使用此方法来获取信号发送对象的。
实际上使用Qt::DirectConnection连接方式,信号的触发和槽函数执行都是在同一个线程中