dynamic_cast的使用条件

今天从学长那里听来一道腾讯的面试题,问的是C++中的dynamic_cast在什么情况下是错误的?我认为这个问题的更好的描述是dynamic_cast的使用条件是什么?

C++提供了两种方式来支持RTTI,dynamic_cast是其中一种,另一种是typeid()。表面上看,dynamic_cast有两种形式:

Base *pBase = new Derived();

Derived *pDerived = dynamic_cast<Derived *> pBase;


Base refBase = Derived();

Derived &refDerived = dynamic_cast<Derived &> refBase


即dynamic_cast用于将基类的引用或指针转化为派生类的引用或指针。但使用条件是:1、基类的指针或引用确实绑定到派生类的对象上;2、只有当基类至少含有一个虚函数的时候才能使用dynamic_cast。原因是RTTI机制依赖于虚函数表(inside C++ object model第一章给出了解释),而dynamic_cast是RTTI的一种,所以必须要有虚函数表的支持,也就是要虚类中至少有一个虚函数。

那么,dynamic_cast有什么好处呢?

我们知道,基类的指针即使指向的是派生类的对象,但通过基类的指针也只能访问到基类中包含的public成员,那如果想要访问派生类中新增的public成员呢?这就需要将基类的的指针动态类型转化为派生类的指针。见以下代码:

#include<iostream>
using namespace std;
class base{
public:
    base(int x):a(x){ }
    virtual void fcn(){ }  //要有虚函数
    int a;
};

class derived:public base{
public:
    derived(int x,int y):base(x),b(y){ }
    int b;
};

int main(){
    base *pbase = new derived(100, 200);
    cout << pbase->a << endl;
    //cout << pbase->b << endl;  //不能通过基类的指针访问派生类新增的public成员
    
    derived *pderived = dynamic_cast<derived *>(pbase);
    
    cout << pderived->a << endl;
    cout << pderived->b << endl;
}

如何对dynamic_cast转化是否成功进行判断,从而选择进行基类的操作还是进行派生类的操作呢?见下面的代码:

#include<iostream>
using namespace std;
class base{
public:
    base(int x):a(x){ }
    virtual void fcn(){ }  //要有虚函数
    int a;
};

class derived:public base{
public:
    derived(int x,int y):base(x),b(y){ }
    int b;
};

int main(){
    base *pbase0 = new base(100);
    base *pbase1 = new derived(100, 200);


    if(NULL != dynamic_cast<derived *>(pbase0)){
        cout << dynamic_cast<derived *>(pbase0)->b << endl;
        cout<<"derived"<<endl;
    }else{
        cout << pbase0->a << endl;
        cout<<"base"<<endl;
    }

    if(derived *pderived = dynamic_cast<derived *>(pbase1)){
        cout << dynamic_cast<derived *>(pbase1)->b << endl;
        cout<<"derived"<<endl;
    }else{
        cout << pbase1->a << endl;
        cout<<"base"<<endl;
    }
}
运行结果如下:

100
base
200
derived

《C++ primer》第5版P731上给出了以下代码框架:

if(Derived *dp = dynamic_cast<derived *>(bp)){

//使用bp指向的Derived对象

}else{

//使用bp指向的Base对象

}

在vs和gcc下测试过:如果bp指向的不是派生类的对象而是基类的对象的话,那么两种编译器下都不能通过编译!!!这样的运行时动态类型判断也就没有意义了。这种写法值得商榷!


如果是引用的话,当转化不成功时会抛出std::bad_cast异常,详见《C++ primer》第5版P731。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`static_cast`和`dynamic_cast`是C++中的两种类型转换操作符,它们的用途和区别如下: 1. `static_cast` 静态转换,主要用于基本类型之间的转换,比如将`int`类型转换为`float`类型等。此外,也可以用于类层次结构中基类和子类之间的转换,但是这种转换需要满足以下两个条件: - 子类对象的指针或引用可以隐式转换为基类对象的指针或引用。 - 基类对象的指针或引用必须明确转换为子类对象的指针或引用。 示例代码如下: ```c++ class Base { public: virtual void func() {} }; class Derived : public Base { public: void func() override {} }; int main() { Base* b = new Derived(); Derived* d = static_cast<Derived*>(b); // 合法,向下转型 Base* b2 = static_cast<Base*>(d); // 合法,向上转型 return 0; } ``` 2. `dynamic_cast` 动态转换,主要用于类层次结构中基类和子类之间的转换,但是与`static_cast`不同的是,`dynamic_cast`会在运行时检查转换是否有效,如果无效则返回空指针或抛出异常(如果是引用类型则抛出`bad_cast`异常)。因此,`dynamic_cast`的安全性更高,但是也会带来一些性能损失。 示例代码如下: ```c++ class Base { public: virtual void func() {} virtual ~Base() {} }; class Derived : public Base { public: void func() override {} }; int main() { Base* b = new Derived(); Derived* d = dynamic_cast<Derived*>(b); // 合法,向下转型 Base* b2 = dynamic_cast<Base*>(d); // 合法,向上转型 Derived* d2 = dynamic_cast<Derived*>(b2); // 不合法,返回空指针 return 0; } ``` 总的来说,`static_cast`用于基本类型之间的转换以及类层次结构中的向上转型和向下转型(需要满足条件),`dynamic_cast`用于类层次结构中的向上转型和向下转型,并且会在运行时检查转换是否有效。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值