870920 Menu

SwingCoder之C++备忘录·14

类型强转

强制类型转换也称为“显式类型转换”,原始类型可直接使用C风格的类型强转。而类类型,如果是派生类指针转为基类指针,无需转换,直接赋值即可。但如果是基类指针转为派生类指针,则必须使用C++提供的cast强制类型转换运算符。即:子类指针和引用可直接赋值给父类指针和引用,但父类转子类,必须显式强转。C++中的强转运算符共4种:

 dynamic_cast<T>:支持运行时类型识别(RTII)的强转,即指向基类的指针或引用转换成指向派生类或者基类的兄弟类的指针或引用。转换不成功则返回空指针。如果可以转换,则返回其子类或兄弟类的指针或引用。该强转依赖于编译器对RTII的支持,也就是:编译器设置中必须开启RTII(开启后,生成的可执行文件会变大)。注意四点:一是某些编译器中,该强转不能跨动态库工作。二是dynamic_cast不能用于没有虚函数的基类。三是该强转的使用前提一般是:有父类指针,但须使用派生类中新增的函数。四是有运行期开销。

 static_cast<T>:通用型类型转换,不支持RTTI,不涉及继承与多态性的类型强转,可避免类型强转时编译器给出警告。如果强转不成功则不会返回空指针。无运行期开销。

 const_cast<T>:可将被转换对象的const属性去掉,即:将常量强转为变量。比如,在某个类的const成员函数中,将this指针进行强转,而后调用该类的非const函数,以实现const函数调用非const函数这一目的(本身,const函数不可以调用非const函数和非const数据成员):
MyClass* ptr = const_cast<MyClass* const>(this);

 reinterpret_cast<T>: 以最低级的位操作模式进行类型之间的强转,最具危险性。也就是:可把任意类型的指针或引用转换为任意类型。通常用于函数指针之间的类型转换。

4种强转运算符的语法(以dynamic_cast<T>为例):
子类类型* 指针 = dynamic_cast<子类类型*>(父类指针);

关于void*指针:可使用static_cast<类型名*>(要强转的void*指针)进行强转。

还有一种隐式的构造转换:某个类若为单参数构造,则可以直接给类的对象赋值:
MyClass obj = 5;

为了避免这种没有意义的隐式强转,可使用explicit关键字,前缀到类的构造函数声明中,以禁用之。

dynamic_cast<T>和static_cast<T>用的较多,const_cast<T>转换往往意味着程序设计有缺陷,而reinterpret_cast<T>转换由于直接使用数据类型的低级位操作模式,极有可能导致不可预知的风险和奇怪的结果,除非确有把握,否则不建议使用。

注意:要进行dynamic_cast<T>转换的父类指针不能为空,必须是有效的,否则程序极有可能运行时崩溃。转换前后最好使用if语句判断一下。
// 将程序默认的LookAndFeel对象强转为当前正在使用的SwingLookAndFeel。
SwingLookAndFeel* laf = dynamic_cast<SwingLookAndFeel*>
(&(LookAndFeel::getDefaultLookAndFeel()));
jassert(laf != nullptr) // 此处没进行指针有效性的检查(判断),但下了一个断言
g.setFont(laf->getAppFont()); // 根据转换后的结果执行后续代码..

另一例强转(对函数的返回值进行强转):
/* getAudioProcessor()函数的返回值为父类的指针,此对象强转为子类的指针,而后直接返回 */
MyAudioProcessor* getProcessor() const
{
return static_cast <MyAudioProcessor*> (getAudioProcessor());
}

内置类型的强转,使用函数式语法即可:
double recordTime = 23.3265;
float currentPos = float (recordTime) + 5.0f; // 或:(float) recordTime + 5.0f;

强制类型转换总是意味着程序设计有缺陷,或隐含风险。因此,尽量避免使用强转。