C++提供了一种新的类型转换运算符,专门用于继承的情形,这种情形在c语言中不存在。
再说dynamic_cast之前,我想先说说static_cast
static_cast用于在相关类型的指针之间进行转换,还可以显示地执行标准数据类型的类型转换—这种转换原本将自动或隐式进行。用于指针时,static_cast实现了基本的编译阶段检查。确保指针被转换为相关类型。这改进了c风格类型转换,在c语言中,可将指向一个对象的指针转换为完全不相关的类型,而编译器不会报错。使用static_cast可将指针向上转换为基类类型,也可向下转换为派生类型。
Base* pBase=new Derived();
Derived* pDerived=static_cast<Derived*>(pBase);
这段代码是没有什么问题的,如果是转化为无关的类指针,
CUnrelated pUnrelated=static_cast<CUnrelated*>(pBase);
然而,static_cast只验证指针类型是否相关,而不会执行任何运行阶段检查,因此我们可以使用static_cast编写如下代码,而编译器不会报错:
Base* pBase=new Base();
Derived* pderived=static_cast<Derived*>(pBase);
其中pDerived实际上指向一个不完整的Derived对象,因此它指向的对象实际上是Base()类型。由于static_cast只在编译阶段检查转换类型是否相关,而不执行运行阶段检查,因此pDerived->someDerivedFunction()能够通过编译,但在运行阶段可能会出意外。
使用dynamic_cast
顾名思义,与静态类型转换相反,动态类型在运行阶段执行类型转换,可检查dynamic_cast操作结果,以判断转换类型是否成功。语法如下:
destination_type* pDest=dynamic_cast<class_type*)(pSource);
if(pDest) //check for success of
//the casting operation before using point
pDest->CallFunc();
eg:
Derived* pDerived=dynamic_cast<Derived*>(pBase);
if(pDerived)
pDerived->callderivedClassFunction();
给定一个指向基类对象的指针,程序员可以使用dynamic_cast进行类型转换,并在使用指针前检查指针指向目标对象的类型。下面给一个完整的例子。
#include <iostream>
using namespace std;
class Fish
{
public:
virtual void Swim()
{
cout << "Fish swims in water" << endl;
}
// base class should always have virtual destructor
virtual ~Fish() {}
};
class Tuna: public Fish
{
public:
void Swim()
{
cout << "Tuna swims real fast in the sea" << endl;
}
void BecomeDinner()
{
cout << "Tuna became dinner in Sushi" << endl;
}
};
class Carp: public Fish
{
public:
void Swim()
{
cout << "Carp swims real slow in the lake" << endl;
}
void Talk()
{
cout << "Carp talked crap" << endl;
}
};
void DetectFishType(Fish* InputFish)
{
Tuna* pIsTuna = dynamic_cast <Tuna*>(InputFish);
if (pIsTuna)
{
cout << "Detected Tuna. Making Tuna dinner: " << endl;
pIsTuna->BecomeDinner(); // calling Tuna::BecomeDinner
}
Carp* pIsCarp = dynamic_cast <Carp*>(InputFish);
if(pIsCarp)
{
cout << "Detected Carp. Making carp talk: " << endl;
pIsCarp->Talk(); // calling Carp::Talk
}
cout << "Verifying type using virtual Fish::Swim: " << endl;
InputFish->Swim(); // calling virtual function Swim
}
int main()
{
Carp myLunch;
Tuna myDinner;
// Carp* MyCarp = &myLunch;
// Fish* MyFish = MyCarp;
// Carp* MyCarpAgain = MyFish;
DetectFishType(&myDinner);
cout << endl;
DetectFishType(&myLunch);
return 0;
}
结果如下:
而如果不适用dynamic_cast来转换,使用强制转换,我们修改一处
void DetectFishType(Fish* InputFish)
{
Tuna* pIsTuna =(Tuna*)InputFish ;//dynamic_cast <Tuna*>(InputFish);
if (pIsTuna)
{
cout << "Detected Tuna. Making Tuna dinner: " << endl;
pIsTuna->BecomeDinner(); // calling Tuna::BecomeDinner
}
我们发现,使用强制转换后,可以将pCarp*类型转换为pTuna*类型,有时候这是我们需要的,有时候是我们不需要的。采用强制转换,即便是pFish类型,也能满足if(pIsTuna)的判断,进而输出,而使用dynamic_cast