您好,登錄后才能下訂單哦!
小編給大家分享一下c++中類型識別作用是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討方法吧!
1、類型識別的相關概念
(1)類型識別的作用
類型識別是面向對象中引入的一個新概念,主要用來判斷賦值兼容性原則中的類型問題,即此時的數據類型到底是基類類型還是派生類類型?
當基類指針指向子類對象 或者基類引用成為子類對象的別名 時,就需要使用類型識別;
Base *p = new Derived(); Base &r = *p
對于上面的語句,我們可以這樣認識,指針p是Base類型,但是P 又指向了一個新的Derived類型,此時很難判斷指針P 的數據類型;同理,引用r 本來作為父類的別名而存在,但由于賦值兼容性,引用r也可以作為子類的別名,同樣此時 引用 r 的數據類型也不能確定;
注:1)由之前所學知識,若沒有虛函數重寫,編譯器為了安全起見,會將指針p 當作 Base 類型;(編譯期間)
2)若有虛函數重寫,就會發生動態多態特性,此時就會根據指針p 所指向的具體數據類型來確定指針p 的數據類型。(運行期間)
(2)類型識別的分類
1)靜態類型:變量(對象)自身的類型;在編譯階段就能確定所使用變量的數據類型。
2)動態類型:指針(引用)所指向對象的實際類型;在運行階段根據指針所指向的具體數據類型來確定所使用的數據類型。
Base *b 所指向的實際對象無法確定,若指針b 指向的是子類對象,則程序正常運行;若指針b 指向的是父類對象,則程序有可能出現 Bug;
注:在 g++ 編譯器下上述情況均可正常運行,但后者不建議使用;
在賦值兼容原則中,基類指針是否可以強制類型轉換為子類指針取決于動態類型;(很重要!!!)--- 只有動態類型是子類對象才能進行合法轉換
2、如何得到動態類型
(1)利用多態
1)必須從基類開始提供類型虛函數;
2)所有的派生類都必須重寫類型虛函數;
3)每個派生類的類型 ID必須唯一;
結果:調用類型虛函數就可以知道當前的對象究竟是什么類型,這樣就可以得到動態類型,達到動態類型識別效果;
利用類型虛函數實現類型識別
#include <iostream> #include <string> using namespace std; class Base { public: enum { ID = 0 }; virtual int type() // 類型虛函數 { return ID; } }; class Derived : public Base { public: enum { ID = 1 }; int type() { return ID; } void print() { cout << "I'm a Derived. " << endl; } }; class Child : public Base { public: enum { ID = 2 }; int type() { return ID; } }; void test(Base* pb) { if( pb->type() == Child::ID ) { Child* pc = static_cast<Child*>(pb); //Child* pc = dynamic_cast<Child*>(pb); // 同上 cout << "& = " << pc << endl; cout << "I'm a Child. " << endl; } if( pb->type() == Derived::ID ) { Derived* pd = static_cast<Derived*>(pb); //Derived* pd = dynamic_cast<Derived*>(pb); // 同上 cout << "& = " << pd << endl; pd->print(); } if( pb->type() == Base::ID ) { cout << "& = " << pb << endl; cout << "I'm a Base. " << endl; } } int main(int argc, char *argv[]) { Base b; Derived d; Child c; test(&b); test(&d); test(&c); return 0; } /** * 運行結果: * & = 0x7ffccf0dd850 * I'm a Base. * & = 0x7ffccf0dd860 * I'm a Derived. * & = 0x7ffccf0dd870 * I'm a Child. */
(2)利用 dynamic_cast
1)dynamic_cast這個關鍵字如果要轉換的實際類型和指定的類型不一樣,則會返回NULL。例如當指定類型為子類對象時,如果父類指針的動態類型是這個子類對象時,轉換成功,而動態類型是父類對象或者其他子類對象時,轉換失敗;
2)dynamic_cast 要求使用的目標對象類型必須是多態,即:所在類族至少有一個虛函數;
3)只能用于指針和引用之間的轉換
1.用于指針轉換時,轉換失敗,返回空指針;
2.用于引用轉換時,轉換失敗,將引發 bad_cast異常。
#include <iostream> #include <string> using namespace std; class Base { public: virtual ~Base() { } }; class Derived : public Base { public: void print() { cout << "I'm a Derived. " << endl; } }; class Child : public Base { }; void test(Base* pb) { // dynamic_cast 只能確定最終的轉化結果,無法獲取動態類型的原型 Derived* pd = dynamic_cast<Derived*>(pb); if(pd != NULL) { // Derived 類類型, 可以使用指針pd訪問Derived類的成員 cout << "& = " << pd << endl; pd->print(); } else { Child* pc = dynamic_cast<Child*>(pb); if(pc != NULL) { // Child 類類型, 可以使用指針pc訪問Child類的成員 cout << "& = " << pc << endl; cout << "I'm a Child. " << endl; } else { // Base 類類型, 可以使用指針pb訪問Base類的成員 cout << "& = " << pc << endl; cout << "I'm a Base. " << endl; } } } int main(int argc, char *argv[]) { Base b; Derived d; Child c; test(&b); test(&d); test(&c); return 0; } /** * 運行結果: * & = 0 * I'm a Base. * & = 0x7ffccf0dd860 * I'm a Derived. * & = 0x7ffccf0dd870 * I'm a Child. */
(3)利用 typeid(推薦這種方法)
1)typeid是一個關鍵字,專門用于動態類型識別;
2)typeid 關鍵字返回對應參數的類型信息,此類型信息是一個type_info類對象;
1.當參數為類型時,返回靜態類型信息;
2.當參數為變量時:1> 參數變量內部不存在虛函數表時,返回靜態類型信息; 2> 參數變量內部存在虛函數表時,返回動態類型信息;
3.當參數為 NULL 時,將拋出異常;
3)typeid使用時需要包含頭文件<typeinfo>;
4)typeid 使用時直接指定對象或者類型。
5)typeid 在不同的編譯器內部實現是不同的;
int i = 0; const type_info& tiv = typeid(i); // 將 i 的類型信息放到 type_info 中去; const type_info& tii = typeid(int); cout << (tiv == tii) << endl; // 1
利用 typeid 實現類型識別
#include <iostream> #include <string> #include <typeinfo> using namespace std; class Base { public: virtual ~Base() { } }; class Derived : public Base { public: void print() { cout << "I'm a Derived." << endl; } }; class Child : public Base { public: void print() { cout << "I'm a Child." << endl; } }; void test(Base* pb) { const type_info& tb = typeid(*pb); if( tb == typeid(Derived) ) { Derived* pd = dynamic_cast<Derived*>(pb); cout << "& = " << pd << endl; pd->print(); } else if( tb == typeid(Child) ) { Child* pc = dynamic_cast<Child*>(pb); cout << "& = " << pc << endl; pc->print(); } else if( tb == typeid(Base) ) { cout << "& = " << pb << endl; cout << "I'm a Base. " << endl; } cout << tb.name() << endl; } int main(int argc, char *argv[]) { Base b; Derived d; Child c; int index; char ch; const type_info& tp = typeid(b); const type_info& tc = typeid(d); const type_info& tn = typeid(c); const type_info& ti = typeid(index); const type_info& tch = typeid(ch); cout<<tp.name()<<endl; cout<<tc.name()<<endl; cout<<tn.name()<<endl; cout<<ti.name()<<endl; cout<<tch.name()<<endl; test(&b); test(&d); test(&c); return 0; } /** * 運行結果: * 4Base * 7Derived * 5Child * i * c * & = 0x7ffcbd4d6280 * I'm a Base. * 4Base * & = 0x7ffcbd4d6290 * I'm a Derived. * 7Derived * & = 0x7ffcbd4d62a0 * I'm a Child. * 5Child */
看完了這篇文章,相信你對c++中類型識別作用是什么有了一定的了解,想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。