前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【C++】类型转换

【C++】类型转换

作者头像
青衫哥
发布2023-10-17 08:45:06
1400
发布2023-10-17 08:45:06
举报
文章被收录于专栏:C++打怪之路C++打怪之路

一、C语言中的类型转换

在 C 语言中,如果 赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与 接收返回值类型不一致时,就需要发生类型转化 , C 语言中总共有两种形式的类型转换: 隐式类型 转换和显式类型转换

1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败

2. 显式类型转化:需要用户自己处理

代码语言:javascript
复制
int main()
{
	//隐式类型转换
	int i = 5;
	double d = i;
	//显式类型转换
	int* pi = &i;
	int address = (int)pi;

	return 0;
}

C风格的转换格式很简单,但是有不少缺点的:

1. 隐式类型转化有些情况下可能会出问题:比如数据精度丢失 2. 显式类型转换将所有情况混合在一起,代码不够清晰

因此 C++ 提出了自己的类型转化风格,注意 因为 C++ 要兼容 C 语言,所以 C++ 中还可以使用 C 语言的 转化风格


二、C++中的类型转换

标准 C++ 为了加强类型转换的可视性,引入了四种命名的强制类型转换操作符: static_cast、reinterpret_cast、const_cast、dynamic_cast

1.static_cast

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

例如:

我们可以用于将 double 类型转化成int类型,但是不可以将 double *类型转化成int类型。

代码语言:javascript
复制
int main()
{
	double d = 5.32;
	int i = static_cast<int>(d);

	double* pd = &d;
	int di = static_cast<int>(pd);
	cout << di << endl;
	return 0;
}

2.reinterpret_cast

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

例如:

我们上面无法将double*转化成int类型,用reinterpret_cast就可以实现。

代码语言:javascript
复制
int main()
{
	double d = 5.32;
	double* pd = &d;
	int di = reinterpret_cast<int>(pd);
	cout << di << endl;
	return 0;
}

3.const_cast

const_cast最常用的用途就是删除变量的const属性,方便赋值

例如:

将const类型的常变量转化为没有const属性的类型

代码语言:javascript
复制
int main()
{
	const int a = 2;
	int* p = const_cast<int*> (&a);
	*p = 3;

	cout << a << endl;
	cout << *p << endl;
	return 0;
}

看到结果,很多人可能就会好奇了,怎么还会打印不同的结果呢?

这是因为,我们用const修饰a类型之后,编译器认为a之后都不会改变,就将a读取到寄存器中,之后读取a的数据都是用存储在寄存器中的数据。当我们用*p修改了a在内存中的值之后,打印a是打印寄存器中a的值,打印*p则是内存中a的值。所以结果会不同。

拓展:volatile

volatile是一个关键字,作用是保持内存的可见性,也就是每次读取数据都会从内存中读取。

代码语言:javascript
复制
int main()
{
	volatile const int a = 2;
	int* p = const_cast<int*> (&a);
	*p = 3;

	cout << a << endl;
	cout << *p << endl;
	return 0;
}

4.dynamic_cast

dynamic_cast用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)

向上转型:子类对象指针 / 引用 -> 父类指针 / 引用 ( 不需要转换,赋值兼容规则 )

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

注意:

1. dynamic_cast 只能用于父类含有虚函数的类(如果是子类含有虚函数而父类不具有,那么无法转换)

2. dynamic_cast 会先检查是否能转换成功,能成功则转换,不能则返回 0

 代码示例:

当我们用强制类型转换的时候,是可能会发生越界问题的。

代码语言:javascript
复制
class Father
{
public:
	virtual void f(){}
private:
	int _a;
};

class Child :public Father
{
public:
	int _b = 2 ;
};

void Func(Father* f)
{
	Child* ch = (Child*)f;
	cout << ch->_b << endl;
}

int main()
{
	Father* th = new Father;
	Child* ch = new Child;
	Func(th);
	Func(ch);
	return 0;
}

 我们再用dynamic_cast来将父类转换成子类

代码语言:javascript
复制
class Father
{
public:
	virtual void f(){}
private:
	int _a;
};

class Child :public Father
{
public:
	int _b = 2 ;
};

void Func(Father* f)
{
	Child* ch = dynamic_cast<Child*>(f);
	if (ch == 0)
	{
		cout << "转换失败" << endl;
		return;
	}
	cout << ch->_b << endl;

}

int main()
{
	Father* th = new Father;
	Child* ch = new Child;
	Func(th);
	Func(ch);
	return 0;
}

 我们可以看到,会出现越界问题的就会转化失败返回0。

这样使得我们的程序更加安全。


三、RTTI

RTTI : Run-time Type identifification 的简称,即:运行时类型识别。

C++ 通过以下方式来支持 RTTI :

1. typeid运算符

2. dynamic_cast运算符

3. decltype

1.typeid运算符

作用:一般我们使用typeid来查看变量的类型。 

格式:typeid(变量).name()

代码示例: 

代码语言:javascript
复制
int main()
{
	int a = 0;
	cout << typeid(a).name() << endl;
	return 0;
}

2. decltype

作用:复制变量的类型作为使用。

格式:decltype(变量) + 新变量名

代码语言:javascript
复制
int main()
{
	int a = 0;
	decltype(a) b = 10;
	cout << b << endl;
	return 0;
}

我们有时候可能会忘记了某个变量的名字,但是查找定义又十分麻烦,为了便于创建一个同类型的变量,我们可以使用decltype。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-06-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、C语言中的类型转换
  • 二、C++中的类型转换
    • 1.static_cast
      • 2.reinterpret_cast
        • 3.const_cast
          • 4.dynamic_cast
          • 三、RTTI
            • 1.typeid运算符
              • 2. decltype
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档