B* b = new D();
D* d = dynamic_cast<D*>(b);
В приведенном выше примере большинство компиляторов реализуют динамическое приведение, проверяя, указывает ли указатель vtable на b на vtable производного класса D или нет.Если да, он просто возвращает адрес b в качестве возвращаемого значения, в противном случае он возвращает nullptr.Это то, что возможно происходит за кулисами, когда выполняется динамическое приведение: -
class car
{
public:
virtual void drive()
{
std::cout <<"car"<<std::endl;
}
};
class toyota: public car
{
public:
virtual void drive()
{
std::cout <<"toyota"<<std::endl;
}
};
class honda: public car
{
public:
virtual void drive()
{
std::cout <<"honda"<<std::endl;
}
};
template <typename Tderived>
Tderived* dynamicCast(void* pBase)
{
//compare the vptr of the class pointed by pBase with a temporary Tderived class.
//If vptr of pBase and vptr of Tderived() are pointing to the same vtable
//then it can be safely deduced that pBase is indeed pointing to an instance of Tderived
if (*(int**)pBase == *(int**)&Tderived())
{
return (Tderived*)pBase;
}
else
{
return nullptr;
}
}
int main()
{
car* pCar;
honda hondaCar;
toyota toyotaCar;
pCar = &toyotaCar;
honda* pHonda = dynamicCast<honda>(pCar);
if (nullptr != pHonda)
{
pHonda->drive();
}
else
{
toyota* pToyota = dynamicCast<toyota>(pCar);
if (nullptr != pToyota)
{
pToyota->drive();
}
}
}
Теперь, если класс не полиморфен, компилятор не сможет определить, указывает ли pCar на honda илиавтомобиль тойота.Обратите внимание, что это только один из способов реализации dynamic_cast, поскольку стандарт C ++ ничего не говорит о vtables.