C++:类型转换

目录

一、C语言中的类型转换

二、C++四种强制类型转换

static_cast

reinterpret_cast

const_cast

dynamic_cast



C++查找手册icon-default.png?t=N7T8https://legacy.cplusplus.com/

一、C语言中的类型转换

        模糊的讲,所有的类型转换都有一个不成文的约束:只有彼此有一定关联的类型才可以互相转换。

        C语言中的类型转换分为:

  • 隐式类型转换
  • 强制类型转换(显式类型转换)

        发生隐式类型转换的情况:

1.整型家族之间(int、short、char)
int i = 10;
char c = i;//编译通过,隐式类型转换
2.整型和浮点数之间
int i = 10;
double d = i;//编译通过、隐式类型转换
3.bool类型和整型
if(0)
while(1)
4.bool类型和指针
while(ptr)

        需要强制类型转换的情况

1.指针和整型
int i = 10;
int* p = &i;

int a = (int)p;//如果不强制类型转换,编译会报错
2.不同类型的指针之间
int i = 10;
int* p = &i;

char c = 'a';
char* pc = &c;

p = (int*)pc;//如果不强制类型转换,编译会报错

        而C++使用面向对象的思想,C++中的类型分为内置类型自定义类型,内置类型的互相转换规则同C语言一样,因此,C++的类型转换更多的讨论是关于内置类型自定义类型之间。

        自定义类型和内置类型之间的转换是通过构造函数支持的。

1.内置类型转换为自定义类型,由相应的构造函数实现,属于隐式类型转换
string s = "abcd";//本质是string支持const char* 的构造函数

const string& ss = "abcd";//引用要使用const,因为类型转换中间都会产生具有常性的临时变量
2.自定义类型转换为自定义类型,也是由构造函数支持
3.自定义类型转换为内置类型,需要特殊的重载函数,比如自定义类型A要转换为int
class A
{
public:
	operator int()
	{
		return _a1 + _a2;
	}
private:
	int _a1 = 1;
	int _a2 = 2;
};

        以上的类型转换规则,由于继承C的风格,有一些缺陷:转换的可视性差难以跟踪错误的转换。

        因此C++在保证兼容C风格的类型转换前提下,引入了四种命名形式的类型转换操作符

二、C++四种强制类型转换

static_cast

        static_cast用于非多态类型的转换(静态转换),编译器隐式执行的任何类型转换都可以用static_cast,但它不能用于两个不相关的类型进行转换。

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;
	return 0;
}

reinterpret_cast

        reinterpret_cast用来规范原来的强制类型转换。

int main()
{
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl;
	// 这里使用static_cast会报错,应该使用reinterpret_cast
	//将int转换为指针
	int* p = reinterpret_cast<int*>(a);
	return 0;
}

const_cast

        const_cast一般用来去掉变量的const属性。

void Test()
{
	const int a = 2;
	int* p = const_cast<int*>(&a);//注意<>的类型一般为指针或引用
	*p = 3;
	cout << a << endl;
}

        运行结果

        可见我们的要求并没有实现(不是)。其实在内存中变量a的值已经修改为了3,但是由于寄存器中还存储着原来的值(因为是常量,并不会轻易修改),所以去掉const属性是会造成内存可视优化风险的,因此新增关键字volatile来解决。

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


dynamic_cast

        dynamic_cast,在继承体系中,一般用于将父类对象的指针或引用动态的转换子类对象的指针或引用(向下转换)。

        在继承体系中,有两种转换的说法。

  • 向上类型转换

        向上转换是指子类对象“转换”为父类对象,本质不是类型转换,而是赋值兼容规则。

class A
{
public:
	int _a = 0;
    virtual void f() {}//该继承体系须支持多态
};

class B : public A
{
public:
	int _b = 1;
};

int main()
{
	//向上类型转换,其实不是类型转换,而是赋值兼容规则,子类向上“转换”为父类
	B bb;
	A aa = bb;
	A* ptr = &bb;
	return 0;
}
  • 向下转换

        向下转换是指父类对象“转换”为子类对象

void fun(A* pa);//A是父类

        根据继承中的语法规则

        如果pa原来指向子类,此时向下转换是安全的。

        如果pa原来指向父类,此时向下转换为子类,会造成越界访问,是不安全的。

        而dynamic_cast就是用来动态转换父子类。

void fun(A* pa)
{
	// 向下转换:父->子
	// pa指向子类对象,转回子类,是安全的
	// pa指向父类对象,转回子类,是不安全的,存在越界的风险问题

	// 传统写法,不安全
	//B* pb = (B*)pa;

	//  pa指向子类对象,转回子类,正常转换
	//  pa指向父类对象,转回子类,转换失败
	B* pb = dynamic_cast<B*>(pa);
	if (pb)
	{
		cout << pb << endl;
		cout << pb->_a << endl;
		cout << pb->_b << endl;
	}
	else
	{
		cout << "转换失败" << endl;
	}
}

RTTI(Run-time Type identification)运行时类型识别

        C++通过以下方式实现RTTI:

  • typeid运算符
  • dynamic_cast运算符
  • decltype 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值