【C++】类型转换

本文详细介绍了C++中的类型转换,包括C语言的基础类型转换、C++新增的static_cast、reinterpret_cast、const_cast和dynamic_cast,以及RTTI在运行时类型识别中的应用,帮助读者理解C++类型系统及其潜在风险。
摘要由CSDN通过智能技术生成

         本篇博客整理了类型转换的形式和情景,介绍了C++中的四个类型转换操作符,旨在让读者更加了解量的类型和特性。       

 

目录

一、C语言的类型转换

二、C++的四种类型转换

1.static_cast

2.reinterpret_cast

3.const_cast

4.dynamic_cast

补、RTTI


一、C语言的类型转换

        在C语言中有两种形式的类型转换:

  • 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
  • 显示类型转化:由用户指定

        而类型转换一般会发生在以下情景:

  1. 赋值运算符或逻辑运算符的左右操作数类型不同;
  2. 形参与实参类型不匹配;
  3. 返回值类型与接收值类型不一致。
class A
{
public:
    //explicit A(int a) //explicit关键字可以阻止自定义类型转换发生
    A(int a)	//单参数的构造支持隐式类型转换
        :_a(a)
    {}
private:
    int _a;
};

class B
{
public:
    B(const A& a)	//此处编译器将构造+拷贝构造优化为构造
    {}
private:
    //...
};


int main()
{
    //c:

    int i = 1;
    // 隐式类型转换 - 发生在含义相关或意义相近的内置类型之间
    double d = i;
    printf("%d, %.2f\n", i, d);

    int* p = &i;
    // 显示的强制类型转换
    int address = (int)p;
    printf("%p, %d\n", p, address);


    //cpp:

    //单参数的构造支持隐式类型转换
    A aa1 = 1;

    //自定义类型之间发生转换需内部有关联(例如,构造+拷贝构造)
    B bb1 = aa1;

    //毫无关联的内置类型之间无法转换
    //vector<int> v;
    //string s;
    //v = (vector<int>)s;

    return 0;
}

        虽然C语言的类型转换较为简单,但其中有不少缺陷,例如:

//隐式类型转换是有隐患的,
//例如在操作数之间,数据精度丢失:
void insert(size_t pos, char ch)
{
	int end = 10;
	while (end >= pos) //end会被强转为size_t,造成死循环
	{
		cout << end << endl;
		//...
		--end;
	}
int main()
{
    insert(0, 'x');
}
//显示类型转换也是有隐患的
//例如访问的安全问题:
int main()
{
	const int n = 10; //n是一个常变量,
	//n = 11;         //不能直接修改,
    //只可以通过类型转换间接修改
	//但转换有安全隐患
	int* p = (int*)&n;
	(*p)++;
	cout << n << endl;	//10
	cout << *p << endl;	//11
	//n实际的值已经变为11,但打印的结果仍是10,这是因为编译器做了优化。
	//编译器认为常变量无法修改,没有在内存中实际取n,
    //而是将n放进了寄存器,或者像宏一样直接将n替换为常量
}
//(接上段代码)
//volatile关键字 - 对于其修饰的变量,编译器每次都去内存读取

int main()
{
	volatile const int n = 10; 
	int* p = (int*)&n;
	(*p)++;
	cout << n << endl;	//11
	cout << *p << endl;	//11
}

        C++支持C语言,也就支持C语言中的类型转换。为了弥补C的缺陷,也为了强化类型转换的可视性,C++引入了四种命名的类型转换操作符:static_cast、reinterpret_cast、const_cast、dynamic_cast。

二、C++的四种类型转换

1.static_cast

        static_cast主要用于非多态类型的转换(即用于意义相近的内置类型之间的转换),对应C语言的隐式类型转化。

int main()
{
	// static_cast用于相关类型/相近类型
	double d = 12.34;
	int a = static_cast<int>(d);
	cout << a << endl; //12

	return 0;
}

2.reinterpret_cast

        reinterpret_cast可以为操作数的位模式提供较低层次的重新解释,将一种类型转换为另一种不同的类型,对应C语言的显示类型转化。

int main()
{
	// reinterpret_cast用于不相关类型
	int* p1 = &a;
	cout << p1 << endl;//010FFA30(32位平台下)
	int address = reinterpret_cast<int>(p1);
	cout << address << endl;//17824304
    //reinterpret_cast可以将整型转换为指针,可以把指针转换为数组,
    //可以在指针和引用里进行来回转换
    //它是一种显示地强制转换(任何强制类型转换都应慎用)

	return 0;
}

3.const_cast

        const_cast最常见的用途就是去掉变量的const属性,以方便赋值,对应C语言的显示类型转化。const_cast也可以看作是一种警示,表示一个变量去除了const属性,需谨慎操作。

int main()
{
	// const_cast可以去掉const属性
	volatile const int n = 10;
	int* p2 = const_cast<int*>(&n);
	cout << *p2 << endl;//10
    //去除常性之后可能留有隐患,应慎用

	return 0;
}

4.dynamic_cast

        dynamic_cast涉及多态,用于将一个父类对象的指针或引用,向下转换为子类对象的指针或引用。

【补】父类和子类之间的类型转换

向上转换:子类指针/引用 => 父类指针/引用(不需要转换,符合赋值兼容规则)
向下转换:父类指针/引用 => 子类指针/引用(会涉及越界,但通过dynamic_cast就是安全的)

//“通过dynamic_cast就是安全的”是指:
//  在向下转换的过程中,
//  一般子类比父类所占空间更大,因此子类的指针能访问的空间一般更多,但这更多的空间并不属于父类,
//  如果原先指向父类的指针,被强制转换成子类的指针,就涉及了访问权限变大,可能造成越界的非法访问。
//强制类型转换并不会理会指针原先指向的是父类还是子类,只管转换;
//而dynamic_cast会先检查能否安全转换,能则转换,不能则返回空指针。
class A	//父
{
public:
	virtual void f() {} //dynamic_cast 只能用于父类含有虚函数的类
	//void f() {}		//不可用

	int _x = 0;
};

class B : public A	//子
{
public:
	int _y = 0;
};

void fun(A* pa)
{
	// dynamic_cast支持向下转换的检查
	B* pb = dynamic_cast<B*>(pa);
	// pa是指向父类对象A的,则转换失败,返回空指针
	// pa是指向子类对象B的,则转换是安全的,正常返回地址
	
	if (pb)
	{
		cout << "转换成功" << endl;
		pb->_x++;
		pb->_y++;
	}
	else
	{
		cout << "转换失败" << endl;
	}
}
int main()
{
	A aa;
	fun(&aa);
	//转换失败

	B bb;
	fun(&bb);
	//转换成功

	return 0;
}

补、RTTI

        RTTI是“Run - time Type identification(运行时类型识别)”的缩写。C++中,以下操作符涉及RTTI:

  1. typeid(配合name()可以获取类型名称)
  2. dynamic_cast(判断一个指针/引用指向的是父类还是子类)
  3. decltype(自动类型推导)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值