Table of Contents
1.dynamic_cast工作原理
2.dynamic_cast介绍
3.static_cast与dynamic_cast
4.typeid
《深度探索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(pb); // OK
}
那么上述dynamic_cast的一个典型实现是:
My_slider的type_info会被编译器产生出来。pb指向的对象的type_info会在运行时通过vptr取得。这两个type_info会被交给runtime library函数,比较之后告诉我们是否吻合。如果吻合,返回转换后的My_slider*;否则返回nullptr。
在运行时使用类型信息就叫做“run-time type identification”, 即RTTI。
downcast:从基类向子类转换;
upcast:从子类向基类转换;
crosscast:多重继承下,从一个基类到兄弟类的转换.如BBwindow到lval_box转换。
对dynamic_cast来说,upcast就像赋值操作一样,并没有多少耗费资源。dynamic_cast是用来解决编译时无法知道转换是否正确的场景。dynamic_cast要求操作对象是指向一个多态类型(含有虚函数)的指针或引用,来进行downcast或crosscast。
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(pb); // OK
My_date* pd2 = dynamic_cast(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(ps); // pc = 0; a Radio has two Components
// ...
}
dynamic_cast可以将一个多态虚基类转换成子类或邻近兄弟类。但是static_cast不能,因为它不会对它的操作对象进行检查类型。
void g(Radio& r)
{
Receiver* prec = &r; // Receiver is an ordinary base of Radio
Radio* pr = static_cast(prec); // OK, unchecked
pr = dynamic_cast(prec); // OK, run-time checked
Storable* ps = &r; // Storable is a virtual base of Radio
pr = static_cast(ps); //error : cannot cast from virtual base
pr = dynamic_cast(ps); // OK, run-time checked
}
编译器无法预知被void*指针指向的内存的信息。因此,对于需要查看对象类型的dynamic_cast而言,它无法对void*进行转换。而static_cast在这种情况下可以做到。
Radio* f1(void* p)
{
Storable* ps = static_cast(p); // trust the programmer
return dynamic_cast(ps);
}
dynamic_cast和static_cast都无法对const指针或私有继承的指针进行转换。static_cast或者reinterpret_cast都无法将操作对象转换成私有基类。
class Users : private set { /* ... */ };
void f2(Users* pu, const Receiver* pcr)
{
static_cast*>(pu); // error : access violation
dynamic_cast*>(pu); // error : access violation
static_cast(pcr); //error : can’t cast away const
dynamic_cast(pcr); //error : can’t cast away const
Receiver* pr = const_cast(pcr); // OK
// ...
}
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》