[C++] - dynamic_cast介绍及工作原理、typeid、type_info

Table of Contents

1.dynamic_cast工作原理

2.dynamic_cast介绍

3.static_cast与dynamic_cast

4.typeid


1.dynamic_cast工作原理

《深度探索C++对象模型》中有个例子:

class Point
{
public:
	Point(float xval);
	virtual ~Point();

	float x() const;
	static int PointCount();

protected:
	virtual ostream& print(ostream& os) const;

	float _x;
	static int _point_count;
};

这个类的内存布局:

type_info是C++ Standard所定义的类型描述器,type_info中放置着每个类的类型信息。virtual table的第一个slot存有type_info的地址。

《The C++ Programming Language》中有个例子:

class My_slider: public Ival_slider { // polymor phic base (Ival_slider has virtual functions)
// ...
};

void g(Ival_box* pb, Date* pd)
{
    My_slider* pd1 = dynamic_cast<My_slider*>(pb); // OK
}

那么上述dynamic_cast的一个典型实现是:

My_slidertype_info会被编译器产生出来。pb指向的对象的type_info会在运行时通过vptr取得。这两个type_info会被交给runtime library函数,比较之后告诉我们是否吻合。如果吻合,返回转换后的My_slider*;否则返回nullptr

 

2.dynamic_cast介绍

在运行时使用类型信息就叫做“run-time type identification, RTTI

downcast:从基类向子类转换;

upcast:从子类向基类转换;

crosscast:多重继承下,从一个基类到兄弟类的转换.BBwindowlval_box转换。

dynamic_cast来说,upcast就像赋值操作一样,并没有多少耗费资源。dynamic_cast是用来解决编译时无法知道转换是否正确的场景。dynamic_cast要求操作对象是指向一个多态类型(含有虚函数)的指针或引用,来进行downcastcrosscast

class My_slider: public Ival_slider { // polymor phic base (Ival_slider has virtual functions)
// ...
};

class My_date : public Date { // base not polymorphic (Date has no virtual functions)
// ...
};

void g(Ival_box* pb, Date* pd)
{
    My_slider* pd1 = dynamic_cast<My_slider*>(pb); // OK
    My_date* pd2 = dynamic_cast<My_date*>(pd); // error : Date not polymorphic
}

多重继承:

class Component
: public virtual Storable { /* ... */ };
class Receiver
: public Component { /* ... */ };
class Transmitter
: public Component { /* ... */ };
class Radio
: public Receiver, public Transmitter { /* ... */ };

这里,一个Radio对象有两个Component基类对象。因此,在一个Radio对象内部从Storable到Component的dynamic_cast是模糊的,将会返回0.

void h1(Radio& r)
{
    Storable* ps = &r; // a Radio has a unique Storable
    // ...
    Component* pc = dynamic_cast<Component*>(ps); // pc = 0; a Radio has two Components
    // ...
}

 

3.static_cast与dynamic_cast

dynamic_cast可以将一个多态虚基类转换成子类或邻近兄弟类。但是static_cast不能,因为它不会对它的操作对象进行检查类型。

void g(Radio& r)
{
    Receiver* prec = &r; // Receiver is an ordinary base of Radio
    Radio* pr = static_cast<Radio*>(prec); // OK, unchecked
    pr = dynamic_cast<Radio*>(prec); // OK, run-time checked
    Storable* ps = &r; // Storable is a virtual base of Radio
    pr = static_cast<Radio*>(ps); //error : cannot cast from virtual base
    pr = dynamic_cast<Radio*>(ps); // OK, run-time checked
}

编译器无法预知被void*指针指向的内存的信息。因此,对于需要查看对象类型的dynamic_cast而言,它无法对void*进行转换。而static_cast在这种情况下可以做到。

Radio* f1(void* p)
{
    Storable* ps = static_cast<Storable*>(p); // trust the programmer
    return dynamic_cast<Radio*>(ps);
}

dynamic_cast和static_cast都无法对const指针或私有继承的指针进行转换。static_cast或者reinterpret_cast都无法将操作对象转换成私有基类。

class Users : private set<Person> { /* ... */ };
void f2(Users* pu, const Receiver* pcr)
{
    static_cast<set<Person>*>(pu); // error : access violation
    dynamic_cast<set<Person>*>(pu); // error : access violation
    static_cast<Receiver*>(pcr); //error : can’t cast away const
    dynamic_cast<Receiver*>(pcr); //error : can’t cast away const
    Receiver* pr = const_cast<Receiver*>(pcr); // OK
    // ...
}

 

4.typeid

typeid()返回指针或引用指向的对象的类型信息type_info。如果typeid()的操作数是nullptr,那么typeid()会抛出std::bad_typeid的异常。

void f(Shape& r, Shape* p)
{
    typeid(r); // type of the object referred to by r
    typeid(*p); // type of the object pointed to by p
    typeid(p); // type of the pointer, that is, Shape* (uncommon, except as a mistake)
}

type_info定义:

class type_info {
    // data
public:
    virtual ˜type_info(); //is polymorphic
    bool operator==(const type_info&) const noexcept; // can be compared
    bool operator!=(const type_info&) const noexcept;
    bool before(const type_info&) const noexcept; // ordering
    size_t hash_code() const noexcept; // for use by unordered_map and the like
    const char* name() const noexcept; // name of type
    type_info(const type_info&) = delete; // prevent copying
    type_info& operator=(const type_info&) = delete; // prevent copying
};

例子:

struct Poly { // polymor phic base class
    virtual void f();
    // ...
};
struct Non_poly { /* ... */ }; // no virtual functions
struct D1 : Poly { /* ... */ };
struct D2 : Non_poly { /* ... */ };

void f(Non_poly& npr, Poly& pr)
{
    cout << typeid(npr).name() << '\n'; // writes something like "Non_poly"
    cout << typeid(pr).name() << '\n'; // name of Poly or a class derived from Poly
}
void g()
{
    D1 d1;
    D2 d2;
    f(d2,d1); // writes "Non_poly D1"
}

 

参考资料:

1.《深度探索C++对象模型》

2.《The C++ Programming Language》

  • 12
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
dynamic_cast是C++中的一个类型转换运算符,用于在继承关系中进行类型转换。它要求操作数必须是多态类型,即父类必须存在虚函数。\[1\]在使用dynamic_cast时,如果转换成功,则返回指向目标类型的指针或引用;如果转换失败,则返回nullptr。\[2\]dynamic_cast的使用需要注意以下几点: 1. dynamic_cast只能用于指针或引用类型的转换,不能用于基本类型的转换。 2. dynamic_cast只能用于具有继承关系的类型之间的转换,即父类和子类之间的转换。 3. dynamic_cast在进行类型转换时,会进行运行时类型检查,因此会带来一定的性能开销。 4. dynamic_cast只能用于向下转型,即将父类指针或引用转换为子类指针或引用。如果尝试将子类指针或引用转换为父类指针或引用,dynamic_cast会返回nullptr。 总之,dynamic_cast是C++中用于在继承关系中进行类型转换的运算符,它要求操作数必须是多态类型,并且只能用于具有继承关系的类型之间的转换。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [c++——dynamic_cast的使用](https://blog.csdn.net/www_dong/article/details/124873017)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [dynamic_cast的详细用法,typeid运算符简介](https://blog.csdn.net/A_With_better/article/details/121862072)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [C++中static_cast和dynamic_cast强制类型转换](https://blog.csdn.net/a1013642808/article/details/80429061)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值