C++类型转换

C++在兼容C的强制类型转换后,提出了自己的类型转换模式

一、C语言中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不陪陪,或者返回值类型与接收返回值类型不一致时,就需要发生类型转换

C语言有两种类型的转换:隐式类型转换显式类型转换

在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型转换为左边变量的类型,这可能会导致数据失真,或者精度降低;所以说,隐式类型转换并不一定是安全的。对于不安全的类型转换,编译器一般会给出警告

无论是隐式类型转换还是显示类型转换,都只是为了本次运算而进行的临时性转换,转换的结果也会保存到临时的内存空间,不会改变数据本来的类型或者值

void Test()
{
    int i = 1;
    // 隐式类型转换
    double d = i;
    printf("%d, %.2f\n", i, d);
    int* p = &i;
    // 显示的强制类型转换
    int address = (int)p;
    printf("%x, %d\n", p, address);
}

二、C++的类型转换

C语言风格的转换格式很简单,但存在如下缺点:①隐式类型转换导致数据精度丢失②显示类型转换混杂所有情况,代码不够清晰

因此C++提供了四种类型转换

1.static_cast

用于非多态类型的转换,任何编译器执行的隐式类型转换都可以使用

static_cast必须用于相关类型的转换

static_cast是编译时静态类型检查,使用static_cast可以尽量发挥编译器的静态类型检查功能,但是并不能保证代码一定“正确”

void test_1()
{
    double d = 12.34;
    int a = static_cast<int>(d);
    cout << a << endl;

}

2.reinterpret_cast

用于为操作数的位模式提供较低层次的重新解释,用于将一种类型转换为另一种类型

一般多用于指针转换

void test_2()
{
    double d = 12.34;
    int a = static_cast<int>(d);
    cout << a << endl;

    // 这里使用static_cast会报错,应该使用reinterpret_cast
    //int *p = static_cast<int*>(a);
    int* p = reinterpret_cast<int*>(a);
}

3.const_cast

用于改变变量的const属性或volatile属性

Volatile意思是“易变的”,应该解释为“直接存取原始内存地址”比较合适。volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。因此再增加volatile关键字,下面的代码中就可以进行修改

const_cast为什么能修改const为非const?

因为const变量不是物理上(将变量写在只读内存区)实现的,而是编译的时候由编译器保证不被修改的

void test_3()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);
    //int* p = (int*)&a;//也可以实现
	*p = 3;
	cout << a << endl;//2
//编译器实际上对a进行了修改,但是由于const限制,编译器对a进行优化,阻止a的改变
    cout << *p << endl;

    //volatile const int a = 2;
    //int* p = const_cast<int*>(&a);
    //*p = 3;
    //cout << a << endl;//3
    //cout << *p << endl;
}

4.dynamic_cast

dynamic的意思是动态的。dynamic_cast也就是动态转换,将父类对象的指针/引用转换为子类对象的指针或引用

向上转型:子类对象的指针/引用->父类指针/引用(不需要使用,子类继承父类,兼容父类)

向下转型:父类对象的指针/引用->子类指针/引用(用dynamic_cast转型时安全的)

注意:①dynamic_cast只能用于父类含有虚函数的类

②dynamic_cast会先检查能否转换成功,如果能则转换,不能则返回0

class A
{
public:
    virtual void f() {}
};
class B : public A
{};


void func(A* pa,const string& s)
{
    cout << "pa指向" << s << endl;
    B* pb1 = (B*)pa;//不安全的
    B* pb2 = dynamic_cast<B*>(pa);//安全的
    cout << "强制转换\tpb1:" << pb1 << endl;
    cout << "dynamic_cast\tpb2:" << pb2 << endl;
}



void test_4()//dynamic_cast动态转换
{
    A a;
    B b;
    func(&a, "指向父类对象");
    func(&b, "指向子类对象");
}

三、RTTI

RTTI(Run-Time Type Identification)-运行时类型识别,使程序能够获取由指针或引用指向对象的实际派生类型

C++为了支持RTTI,提供了dynamic_cast、typeid、decltype三种方法

1.typeid

typeid会将获取到的类型信息保存到一个type_info类型对象中,并返回该对象的const引用。如果需要具体的类型信息,可以通过成员函数来提取

为了减小编译后文件的体积,编译器不会为所有类型创建type_info对象,只会为使用了typeid运算符的类型创建。只有带虚函数的类,不论是否使用typeid运算符,编译器都会创建type_info对象

typeid是操作符,而不是函数

#include<iostream>
#include<typeinfo>//需要添加的头文件
using namespace std;
void main()
{
	//typeid().name()可以返回变量、函数、类的数据类型名,功能是相当强大的
	//注意:对非引用类型,typeid().name()是在编译时期识别的,只有引用类型才会在运行时识别
 
	const int a = 10;
	cout << typeid(&a).name() << endl;//const int *
 
	cout << typeid(typeid(a).name()).name() << endl;
	
	//结果为char const *,因此typeid().name()返回了存储类型名的字符串。
	
	
 
}

注意:不可以使用typeid().name()作为变量类型

2.decltype

 decltype是一种类型说明符,目的是解决复杂类型的什么。decltype并不计算表达式的值,而是通过编译器分析表达式并得到它的类型

①作用于变量直接得到变量的类型;②作用于表达式,结果是左值的表达式得到类型的引用,结果是右值的表达式得到类型;③作用于函数名会得到函数类型,不会自动转换成指针。

const int ci = 0, &cj = ci;

// x的类型是const int
decltype(ci) x = 0;

// y的类型是const int &
decltype(cj) y = x;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值