1、類型識別的相關(guān)概念

          (1)類型識別的作用

            類型識別是面向?qū)ο笾幸氲囊粋€(gè)新概念,主要用來判斷賦值兼容性原則中的類型問題,即此時(shí)的數(shù)據(jù)類型到底是基類類型還是派生類類型?

            當(dāng)基類指針指向子類對象? 或者?基類引用成為子類對象的別名? 時(shí),就需要使用類型識別;
          1 Base *p = new Derived(); 2 Base &r = *p
          ? ? ? ?對于上面的語句,我們可以這樣認(rèn)識,指針p是Base類型,但是P 又指向了一個(gè)新的Derived類型,此時(shí)很難判斷指針P
          的數(shù)據(jù)類型;同理,引用r 本來作為父類的別名而存在,但由于賦值兼容性,引用r也可以作為子類的別名,同樣此時(shí) 引用 r 的數(shù)據(jù)類型也不能確定;

            注:1)由之前所學(xué)知識,若沒有虛函數(shù)重寫,編譯器為了安全起見,會(huì)將指針p 當(dāng)作 Base 類型;(編譯期間)    

              2)若有虛函數(shù)重寫,就會(huì)發(fā)生動(dòng)態(tài)多態(tài)特性,此時(shí)就會(huì)根據(jù)指針p 所指向的具體數(shù)據(jù)類型來確定指針p 的數(shù)據(jù)類型。(運(yùn)行期間)

          (2)類型識別的分類

              

            1)靜態(tài)類型:變量(對象)自身的類型;在編譯階段就能確定所使用變量的數(shù)據(jù)類型。

          ??   2)動(dòng)態(tài)類型:指針(引用)所指向?qū)ο蟮膶?shí)際類型;在運(yùn)行階段根據(jù)指針?biāo)赶虻木唧w數(shù)據(jù)類型來確定所使用的數(shù)據(jù)類型。

              

              Base *b 所指向的實(shí)際對象無法確定,若指針b 指向的是子類對象,則程序正常運(yùn)行;若指針b 指向的是父類對象,則程序有可能出現(xiàn) Bug;

              注:在 g++ 編譯器下上述情況均可正常運(yùn)行,但后者不建議使用;

          ?  在賦值兼容原則中,基類指針是否可以強(qiáng)制類型轉(zhuǎn)換為子類指針取決于動(dòng)態(tài)類型;(很重要?。。。?-- 只有動(dòng)態(tài)類型是子類對象才能進(jìn)行合法轉(zhuǎn)換

          2、如何得到動(dòng)態(tài)類型

          (1)利用多態(tài)

            1)必須從基類開始提供類型虛函數(shù);

            2)所有的派生類都必須重寫類型虛函數(shù);

            3)每個(gè)派生類的類型 ID必須唯一;

             結(jié)果:調(diào)用類型虛函數(shù)就可以知道當(dāng)前的對象究竟是什么類型,這樣就可以得到動(dòng)態(tài)類型,達(dá)到動(dòng)態(tài)類型識別效果;
          1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6
          class Base 7 { 8 public: 9 enum { ID = 0 }; 10 11 virtual int type() // 類型虛函數(shù)
          12 { 13 return ID; 14 } 15 }; 16 17 class Derived : public Base 18 { 19 public
          :20 enum { ID = 1 }; 21 22 int type() 23 { 24 return ID; 25 } 26 27 void
          print()28 { 29 cout << "I'm a Derived. " << endl; 30 } 31 }; 32 33 class
          Child :public Base 34 { 35 public: 36 enum { ID = 2 }; 37 38 int type() 39 { 40
          return ID; 41 } 42 }; 43 44 void test(Base* pb) 45 { 46 if( pb->type() ==
          Child::ID )47 { 48 Child* pc = static_cast<Child*>(pb); 49 //Child* pc =
          dynamic_cast<Child*>(pb);// 同上 50 51 cout << "& = " << pc << endl; 52 cout << "
          I'm a Child." << endl; 53 } 54 55 if( pb->type() == Derived::ID ) 56 { 57
          Derived* pd = static_cast<Derived*>(pb); 58 //Derived* pd =
          dynamic_cast<Derived*>(pb);// 同上 59 60 cout << "& = " << pd << endl; 61 pd->
          print();62 } 63 64 if( pb->type() == Base::ID ) 65 { 66 cout << "& = " << pb
          << endl; 67 cout << "I'm a Base. " << endl; 68 } 69 } 70 71 int main(int argc,
          char *argv[]) 72 { 73 Base b; 74 Derived d; 75 Child c; 76 77 test(&b); 78
          test(&d); 79 test(&c); 80 81 return 0; 82 } 83 /** 84 * 運(yùn)行結(jié)果: 85 * & =
          0x7ffccf0dd85086 * I'm a Base. 87 * & = 0x7ffccf0dd860 88 * I'm a Derived. 89
          * & = 0x7ffccf0dd87090 * I'm a Child. 91 */ 利用類型虛函數(shù)實(shí)現(xiàn)類型識別
          ?

          ?(2)利用 dynamic_cast


            1)dynamic_cast這個(gè)關(guān)鍵字如果要轉(zhuǎn)換的實(shí)際類型和指定的類型不一樣,則會(huì)返回NULL。例如當(dāng)指定類型為子類對象時(shí),如果父類指針的動(dòng)態(tài)類型是這個(gè)子類對象時(shí),轉(zhuǎn)換成功,而動(dòng)態(tài)類型是父類對象或者其他子類對象時(shí),轉(zhuǎn)換失??;

            2)dynamic_cast 要求使用的目標(biāo)對象類型必須是多態(tài),即:所在類族至少有一個(gè)虛函數(shù);

            3)只能用于指針和引用之間的轉(zhuǎn)換

              1.?用于指針轉(zhuǎn)換時(shí),轉(zhuǎn)換失敗,返回空指針;

              2.?用于引用轉(zhuǎn)換時(shí),轉(zhuǎn)換失敗,將引發(fā) bad_cast異常。
          1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6
          class Base 7 { 8 public: 9 virtual ~Base() 10 { 11 12 } 13 }; 14 15 class
          Derived :public Base 16 { 17 public: 18 void print() 19 { 20 cout << "I'm a
          Derived." << endl; 21 } 22 }; 23 24 class Child : public Base 25 { 26 27 }; 28
          29 void test(Base* pb) 30 { 31 // dynamic_cast 只能確定最終的轉(zhuǎn)化結(jié)果,無法獲取動(dòng)態(tài)類型的原型 32
          Derived* pd = dynamic_cast<Derived*>(pb); 33 34 if(pd != NULL) 35 { 36 //
          Derived 類類型, 可以使用指針pd訪問Derived類的成員 37 cout << "& = " << pd << endl; 38 pd->
          print();39 } 40 else 41 { 42 Child* pc = dynamic_cast<Child*>(pb); 43 44 if
          (pc != NULL) 45 { 46 // Child 類類型, 可以使用指針pc訪問Child類的成員 47 cout << "& = " << pc
          << endl; 48 cout << "I'm a Child. " << endl; 49 } 50 else 51 { 52 // Base
          類類型, 可以使用指針pb訪問Base類的成員 53 cout << "& = " << pc << endl; 54 cout << "I'm a Base.
          " << endl; 55 } 56 } 57 } 58 59 int main(int argc, char *argv[]) 60 { 61
          Base b;62 Derived d; 63 Child c; 64 65 test(&b); 66 test(&d); 67 test(&c); 68
          69 return 0; 70 } 71 /** 72 * 運(yùn)行結(jié)果: 73 * & = 0 74 * I'm a Base. 75 * & =
          0x7ffccf0dd86076 * I'm a Derived. 77 * & = 0x7ffccf0dd870 78 * I'm a Child.
          79 */ 利用 dynamic_cast 實(shí)現(xiàn)類型識別
          ?

          ?(3)利用 typeid(推薦這種方法)

            1)typeid?是一個(gè)關(guān)鍵字,專門用于動(dòng)態(tài)類型識別;

            2)typeid 關(guān)鍵字返回對應(yīng)參數(shù)的類型信息,此類型信息是一個(gè)type_info類對象;

              1.?當(dāng)參數(shù)為類型時(shí),返回靜態(tài)類型信息;

              2.?當(dāng)參數(shù)為變量時(shí):1>? ?參數(shù)變量內(nèi)部不存在虛函數(shù)表時(shí),返回靜態(tài)類型信息;??? 2>? ?參數(shù)變量內(nèi)部存在虛函數(shù)表時(shí),返回動(dòng)態(tài)類型信息;

              3.?當(dāng)參數(shù)為 NULL 時(shí),將拋出異常;

          ? ? 3)typeid??使用時(shí)需要包含頭文件<typeinfo>;

            4)typeid? 使用時(shí)直接指定對象或者類型。

            5)typeid 在不同的編譯器內(nèi)部實(shí)現(xiàn)是不同的;
          1 int i = 0; 2 3 const type_info& tiv = typeid(i); // 將 i 的類型信息放到 type_info 中去;
          4 const type_info& tii = typeid(int); 5 6 cout << (tiv == tii) << endl; // 1
          ?
          1 #include <iostream> 2 #include <string> 3 #include <typeinfo> 4 5 using
          namespace std; 6 7 class Base 8 { 9 public: 10 virtual ~Base() 11 { 12
          } 13 }; 14 15 class Derived : public Base 16 { 17 public: 18 void print()
          19 { 20 cout << "I'm a Derived." << endl; 21 } 22 }; 23 24 class Child :
          public Base 25 { 26 public: 27 void print() 28 { 29 cout << "I'm a Child."
          << endl; 30 } 31 }; 32 33 void test(Base* pb) 34 { 35 const type_info&
          tb = typeid(*pb); 36 37 if( tb == typeid(Derived) ) 38 { 39 Derived* pd =
          dynamic_cast<Derived*>(pb); 40 41 cout << "& = " << pd << endl; 42 pd->
          print(); 43 } 44 else if( tb == typeid(Child) ) 45 { 46 Child* pc =
          dynamic_cast<Child*>(pb); 47 48 cout << "& = " << pc << endl; 49 pc->print();
          50 51 } 52 else if( tb == typeid(Base) ) 53 { 54 cout << "& = " << pb <<
          endl; 55 cout << "I'm a Base. " << endl; 56 } 57 58 cout << tb.name() <<
          endl; 59 } 60 61 int main(int argc, char *argv[]) 62 { 63 Base b; 64
          Derived d; 65 Child c; 66 int index; 67 char ch; 68 69 const type_info& tp
          = typeid(b); 70 const type_info& tc = typeid(d); 71 const type_info& tn =
          typeid(c); 72 const type_info& ti = typeid(index); 73 const type_info& tch =
          typeid(ch); 74 75 cout<<tp.name()<<endl; 76 cout<<tc.name()<<endl; 77
          cout<<tn.name()<<endl; 78 cout<<ti.name()<<endl; 79 cout<<tch.name()<<endl;
          80 81 test(&b); 82 test(&d); 83 test(&c); 84 85 return 0; 86 } 87 /** 88
          * 運(yùn)行結(jié)果: 89 * 4Base 90 * 7Derived 91 * 5Child 92 * i 93 * c 94 * & =
          0x7ffcbd4d6280 95 * I'm a Base. 96 * 4Base 97 * & = 0x7ffcbd4d6290 98 *
          I'm a Derived. 99 * 7Derived 100 * & = 0x7ffcbd4d62a0 101 * I'm a Child. 102
          * 5Child103 */ 利用 typeid 實(shí)現(xiàn)類型識別
          ? ? ?結(jié)論:

            3 種動(dòng)態(tài)類型的實(shí)現(xiàn)方法 建議選 第3種 (typeid)。

            對于多態(tài)實(shí)現(xiàn),存在以下缺陷:

              1)必須從基類開始提供類型虛函數(shù);

          ? ? ?   ?2)所有的派生類都必須重寫類型虛函數(shù);

          ? ? ? ?  3)每個(gè)派生類的類型名必須唯一;

            對于 dynamic_cast 實(shí)現(xiàn),只能得到類型轉(zhuǎn)換的結(jié)果,不能獲取真正的動(dòng)態(tài)類型,同時(shí)?dynamic_cast 必須多態(tài)實(shí)現(xiàn)。

          ?

          友情鏈接
          ioDraw流程圖
          API參考文檔
          OK工具箱
          云服務(wù)器優(yōu)惠
          阿里云優(yōu)惠券
          騰訊云優(yōu)惠券
          京東云優(yōu)惠券
          站點(diǎn)信息
          問題反饋
          郵箱:[email protected]
          QQ群:637538335
          關(guān)注微信

                中文字幕乱伦无码 | 国产精品日韩无码有码 | 一级做a爱片性色毛片 | 久久青青| 婷婷五情天综合免费 |