在C++中,有哪4个与类型转换相关的关键字?这些关键字各有什么特点,应在什么场合下使用?
答:
一、C++中与类型转换相关的关键字有:static_cast
,const_cast
,dynamic_cast
,reinterpret_cast
这四个类型转换符。强制转换运算符是一种特殊的运算符,它把一种数据类型转换为另一种数据类型。
啥是类型转换呢?
在c++中的数据类型转换一般有以下几种情况:
- 将一种算术类型的值赋给另一种算术类型的变量时,c++将对值进行转换
- 表达式中包含不同的类型时,c++将对值进行转换
- 将参数传递给函数时,c++将对值进行转换
强制类型转换方法:
- 在C语言中的写法就是
(typeName) value
或者value(typeName)
,例如:
int main()
{
(int *) malloc(0); // (Type)Value形式的强制类型转换int(0.);
int(0.); // Type(Value)形式的强制类型转换
}
上述代码中,我们分别使用了C语言的提供的两种强制类型转换的等价形式将void 转为了int ,以及将double转为了int。
value (typeName)
(C++的写法)static_cast<typeName> (value)
可以将值从一种数值类型转换为另外一种数据类型const_cast <typeName> ( value )
dynamic_cast<typeName> (value)
reinterpret_cast
二、详细介绍C++中的这4个与类型转换的关键字:
static_cast
static_cast在C++中就相当于C语言中的强制类型转换语法,用于在编译期对某种类型的变量进行强制类型转换。
参考代码:
int main()
{
static_cast<int*>(malloc(0));
static_cast<int>(0.);
}
上述代码中,我们使用了static_cast分别将void*
转换为了int*
,以及将double转为了int。
const_cast
const_cast是C++中用于处理与const相关的强制类型转换关键字。其功能为:为一个变量重新设定其const描述。可以为一个变量强行增加或者删除其const限定。
需要明确的是,即使用户通过 constcast 强行去除了 const 属性,也不代表当前变量从不可变变为了可变。constcast 只是使得用户接管了编译器对于 const 限定的管理权,故用户必须遵守 " 不修改变量 " 的承诺。如果违反此承诺,编译器也不会因此而引发编译时错误,但可能引发运行时错误。
参考代码:
struct A
{
A &test() {return *this;}
};
int main()
{
//1.
A().test();
//2.
const A a;
a.test();//Error 试图用const对象去调用非const成员函数,出错
}
修改后:
struct A
{
const A &test() const {return *this;}
};
int main()
{
//3.
const A a;
a.test();//解决了const对象调用函数的问题,但若是一个非const对象调用此方法的话其返回值会被转为const,从而不再可以继续调用任何接收A *this的成员函数。
}
解决方法:我们可以为test成员函数同时定义const与非const版本:
struct A
{
A &test() {return *this;}
const A &test() const {return *this;}
A &test2() {return *this;}
}
int main()
{
A().test().test2(); //非const实例调用函数,与非const版本匹配,返回一个 A &
const A a;
a.test(); //const实例调用函数,与const版本函数匹配,返回一个const A &
}
我们基于const的有无重载出了两个版本的成员函数,从而使得const对象与非const对象能够各自调用不同的版本,互不影响。
实际,我们定义的两个重载函数除了 const
外无任何区别,因此可以使用 const_cast
定义第二个重载版本而无需写两遍一模一样的函数体。 参考代码:
struct A
{
//非const版
A &test(){ ... }
//const版
//通过const_cast强行取出this的const限定后调用非const版本
//返回值通过隐式类型转换再转回const A &
const A &test() const {return const_cast<A *>(this)->test();}
}
先定义了一个非const版本的test成员函数,提供给A *this调用;在定义test成员函数的const版本时,我们通过const_cast<A*>(this)
将此版本的const A *this
指针转换为非const版本需要的A *this
类型指针,然后调用了非const版本的test成员函数并返回其调用结果,非const版本的test成员函数的返回值将通过隐式类型转换为const A &
。
通过const_cast,仅需一行代码就可以完成第二个函数重载版本的定义。
dynamic_cast
dynamic_cast 的使用必须同时满足以下所有条件:
被转换的变量的类型为基类指针或引用,且其确实存放了一个继承类指针或引用,基类具有虚表,即基类必须至少定义了一个虚函数。
struct A {virtual void test() {}};//基类含有虚函数
struct B: A {void test2() {}}; //继承类特有函数
int main()
{
//静态类型为基类指针的变量存放继承类指针
A *b = new B;
//通过向下类型转换调用继承类特有函数
dynamic_cast<B *>(b)->test2();
}
由于 test2 成员函数并未在基类中注册为虚函数,我们将无法通过静态类型为 A *
的变量 b 调用此函数。但由于我们可以确定变量 b 的动态类型为 B *
,则可以于运行时通过 dynamic_cast 将变量 b 的静态类型转为 B *,然后调用继承类的特有函数 test2。
reinterpret_cast
reinterpret即重新解释,作用是提供某个变量在底层数据上的重新解释。当我们对一个变量使用reinterpret_cast之后,编译器将无视任何不合理的行为,强行将被转换变量的内存数据解释为某个新的类型。但其要求转换前后类型所占用内存大小一致,否则将引发编译时错误。
int main()
{
reinterpret_cast<int *>(0);//强行将一个整数的内存数据解释为一个int *
}
参考资料:点此