C++11四种类型转换

本文介绍了C++11中的四种类型转换:static_cast(编译时类型检查)、dynamic_cast(运行时类型检查)、reinterpret_cast和const_cast。详细讨论了每种转换的用途、特点和潜在风险,包括在类层次结构中的应用、动态类型检查、内存管理和智能指针的考虑。同时提到了C++11的override关键字的作用,以及volatile关键字的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考:
https://blog.youkuaiyun.com/shidantong/article/details/80864149 (写的超棒!没有写一大堆让人头疼的东西)

C++为了规范C中的类型转换,引入了四种强制类型转换操作;

1.static_cast(编译时类型检查)

相当于C中的隐式类型转换,c++中的隐式类型转换就是使用static_cast。不能用于两个不相关类型的转换

/*基本类型转换*/
void Test(){
	int i=10;
	double d1=i;//隐式类型转换
	double d2=static_cast<double>(i);
}

有一种值得注意的情况: static_cast也可以用于类层次结构中父类和子类之间(自定义类型)指针和引用的转换。不一定包含虚函数。这种转换方式是不安全的。

class A{
	public:
		A(int a):_a(a){}//这里涉及到C++11的一些构造函数
	private:
		int _a;
};
void Test(){
	A a1(10);
	A a2=20;//OK 隐式转换,等价于	A a2=A(20);
	A a3=static_cast<A>(30);
}

因此,单参的构造函数会进行隐式类型转换,C++中即可用static_cast来转。但是这种隐式类型转换有时候是不安全的,尤其是在使用智能指针时,当我们将一个不需要用户自己管理释放空间的指针交给智能指针时,系统并不会报错,但是智能能指针使用完会调用析构函数来释放空间,此时就会出问题。

为了防止这种单参构造函数的隐式类型转换,C++提供了一个关键字 explicit来消除这种隐式转换。

2.dynamic_cast(运行时类型检查)

保证下行转换不会出错(这里又牵扯到内存问题 )只能接受引用,指针,内置对象。

/*强制类型转换*/
void Test(){
	int i=10;
	double d1=i;//隐式类型转换
	double d2=static_cast<double>(i);
}
/*父类与子类之间的转换*/
class Base{
	public:
		virtual void f(){
			cout<<"base f()"<<endl;
		}
	private:
		int _a1;
};
class Derivedpublic Base{
	public:
		virtual void f() override{
			cout<<"derived f()"<<endl;
		}
	private:
		int _a2;
};
void Test(){
	Base* b=new Derived();
	Derived* d1=static_cast<Derived*>(b);
	Derived* d1=dynamic_cast<Derived*>(b);
	/*上面都能成功*/
	Base* b=new Base();
	Derived* d1=static_cast<Derived*>(b);
	Derived* d1=dynamic_cast<Derived*>(b);//失败
}

对于上行转换,dynamic_cast和static_cast是一样的。

注意:
1.dynamic_cast只能用于含有虚函数的类;由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才有虚函数表。
2.dynamic_cast在转换时会先检查能否转换成功,能就进行转换,不能就返回0

C++11 override的作用

作用:

  • 在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的);
  • 强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。

简单来说就是override表示当前函数重写了基类的虚函数,(防止由于粗心本身打算重写却写错了变成别的函数)详见

3.reinterpret_cast

字面意思重新解释,相当于C中的强制类型转换,可将一种类型转换成另一种不相关类型

void Test(){
	int i=10;
	int* p1=(int*)i;//强制类型转换
	int* p2=reinterpret_cast<int*>(i);
}

4.const_cast

作用:

  • 去除指针或引用的const属性。
  • 将常量对象强转为非常量对象
  • 修改类型的volatile属性!??

简单的说一下const能够放在两个位置,放在变量类型左边表示该变量是const,放在右边说明该指针是const不能被修改

void Test(){
	int i = 10;
    const int* p1 =&i;//去除指针的const
    int* p2=const_cast<int*>(p1);
    //*p1=20;//error
    *p2=20;//正确,p1,p2,i的值相同,地址相同
    
	int a = 2;
    const int &c_a = a;//去除引用的const
    //c_a = 5;//错误,常量不能改变
    int &a2 = const_cast<int&>(c_a);
    a2 = 5;//正确,a,a2,c_a的值均为5,地址相同
}

但是!!!!

void Test(){
	const int i=10;
	int* p=const_cast<int*>(&i);
	int& ref_i=const_cast<int&>(i);
	*p=20;
	cout<<i<<endl;//10
	cout<<*p<<endl;//20
	cout<<ref_i<<endl;//20
}

i的值可以修改,但p,&i,&ref_i明明地址相同!结果却不一样。

关键字volatile
这是因为一旦将一个变量定义成const类型,编译器会进行优化,将该值放在寄存器中,默认他是不能被改变的,每次在使用时直接从寄存器中取数据,即使我们改变了他在内存中的值。

我们可以借助一个关键字volatile,保证每次从内存中读取数据。和 const 修饰词类似,const 有常量指针和指针常量的说法,volatile 也有相应的概念:

修饰由指针指向的对象、数据是 const 或 volatile 的:

const char* cpch;
volatile char* vpch;

修饰指针自身

char* const pchc;
char* volatile pchv;

因此可以:

volatile const int i = 10;//可以都输出20,

Ps. 为找工作做准备,尽量关联面经中知识点

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值