RTTI算是C++的一大特性之一了,但也是一個不太好懂的特性。以前一直沒有理解清楚RTTI。通過最近的學習,似乎掌握了一點皮毛,這裡做一個小總結。首先是《C++編程思想》上的一個例子,由於缺頭文件,我把容器改成了vector。
#include#include #include #include #include //for srand() and rand() using namespace std; class shape { protected: static int count; public: shape() { count++; } virtual ~shape() { count--; } virtual void draw() const = 0; static int quantity() {return count;} }; int shape::count = 0; class rectangle:public shape { void operator=(rectangle&); protected: static int count; public: rectangle() {count++;} ~rectangle() {count--;} rectangle(const rectangle&) {count++;} void draw() const { cout << "rectangle::draw()"< shapes; time_t t; srand((unsigned)time(&t)); const int mod = 12; for(int i = 0;i draw(); if(dynamic_cast (shapes[u])) Ncircles++; if(dynamic_cast (shapes[u])) Nellipses++; if(dynamic_cast (shapes[u])) Nrects++; if(dynamic_cast (shapes[u])) Nshapes++; } cout << endl < 下面總結一下幾個知識要點,條理不一定清楚;
(1)、指針是另一種類型;
int和int*是不同的,比如shape* s = new shape,其typeid(s) == typeid(shape*);而typeid(shape) == typeid(*s)。
(2)、引用等同於被引用類型;
這句話說起來非常拗口,但是道理就是這樣。本質上引用是閹割版的指針,但是在C++語言層面上還是有很大區別的,它是一個獨立的類型,它是和類型實例綁定在一起的。下面這個例子可以同時解釋第一條。class B { public: virtual float f() {return 1.0;} }; class D : public B { }; B* p = new D; B& r = *p;typeid()看到的指針類型是基類而不是派生類,這證明了第一條結論,此時的p是一個B型的指針類型,typeid()不會去管指針實際指向的目標。typeid()它看到的引用類型則是派生類,*p是使用p進行了一次指針運算操作,然後r就綁定到了一個D型的實例,也就是說引用的關注點在對象上。
typeid(p) == typeid(B*)
typeid(p) != typeid(D*)
typeid(r) == typeid(D)
與此相反,指針指向的類型在typeid()看來是派生類而不是基類,而用一個引用的地址時產生的是基類而不是派生類。這是因為*p依然是一次指針運算操作,它指向了一個對象,而對引用取地址得到的是一個指針類型,相當於對類型實例做了一次取地址運算。
typeid(*p) == typeid(D)
typeid(*p) != typeid(B)
typeid(&r) == typeid(B*)
typeid(&r) != typeid(D*)
(3)、RTTI一般用於多態類型;
多態類型指的是基類中沒有虛函數的類型。典型的RTTI是通過在 VTABLE中放一個額外的指針來實現的。這個指針指向一個描述該特定類型的 typeinfo結構(每個新類只產生一個typeinfo的實例),所以typeid()表達式的作用實際上很簡單。VPTR用來取typeinfo的指針,然後產生一個結果typeinfo結構的一個引用。dynamic_cast()的過程稍微復雜點,但也需要利用VTABLE中的信息來進行類型轉換。
我不知道怎麼去訪問到VTABLE的typeinfo信息,倒是在找到了一個訪問VTABLE中函數信息的例子。這個例子告訴我們VTABLE不止在書上,感興趣的可以運行一下,或者改改,有可能能找到typeinfo喲!
#includeusing namespace std; class Base { private: int a; public: virtual void fun1() { cout<<"Base::fun1()"<