溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

c++中類(lèi)型識(shí)別作用是什么

發(fā)布時(shí)間:2020-07-01 10:32:57 來(lái)源:億速云 閱讀:143 作者:清晨 欄目:開(kāi)發(fā)技術(shù)

小編給大家分享一下c++中類(lèi)型識(shí)別作用是什么,希望大家閱讀完這篇文章后大所收獲,下面讓我們一起去探討方法吧!

1、類(lèi)型識(shí)別的相關(guān)概念

(1)類(lèi)型識(shí)別的作用

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

  當(dāng)基類(lèi)指針指向子類(lèi)對(duì)象 或者基類(lèi)引用成為子類(lèi)對(duì)象的別名 時(shí),就需要使用類(lèi)型識(shí)別;

Base *p = new Derived();
Base &r = *p

對(duì)于上面的語(yǔ)句,我們可以這樣認(rèn)識(shí),指針p是Base類(lèi)型,但是P 又指向了一個(gè)新的Derived類(lèi)型,此時(shí)很難判斷指針P 的數(shù)據(jù)類(lèi)型;同理,引用r 本來(lái)作為父類(lèi)的別名而存在,但由于賦值兼容性,引用r也可以作為子類(lèi)的別名,同樣此時(shí) 引用 r 的數(shù)據(jù)類(lèi)型也不能確定;

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

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

(2)類(lèi)型識(shí)別的分類(lèi)

c++中類(lèi)型識(shí)別作用是什么

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

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

c++中類(lèi)型識(shí)別作用是什么

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

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

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

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

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

  1)必須從基類(lèi)開(kāi)始提供類(lèi)型虛函數(shù);

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

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

   結(jié)果:調(diào)用類(lèi)型虛函數(shù)就可以知道當(dāng)前的對(duì)象究竟是什么類(lèi)型,這樣就可以得到動(dòng)態(tài)類(lèi)型,達(dá)到動(dòng)態(tài)類(lèi)型識(shí)別效果;

利用類(lèi)型虛函數(shù)實(shí)現(xiàn)類(lèi)型識(shí)別

 #include <iostream>
 #include <string>
 
 using namespace std;
 
 class Base
 {
 public:
   enum { ID = 0 };
   
   virtual int type() // 類(lèi)型虛函數(shù)
   {
     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;
 }
 /**
 * 運(yùn)行結(jié)果:
 * & = 0x7ffccf0dd850
 * I'm a Base. 
 * & = 0x7ffccf0dd860
 * I'm a Derived.
 * & = 0x7ffccf0dd870
 * I'm a Child.
 */

(2)利用 dynamic_cast

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

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

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

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

    2.用于引用轉(zhuǎn)換時(shí),轉(zhuǎn)換失敗,將引發(fā) 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 只能確定最終的轉(zhuǎn)化結(jié)果,無(wú)法獲取動(dòng)態(tài)類(lèi)型的原型
   Derived* pd = dynamic_cast<Derived*>(pb);
   
   if(pd != NULL)
   {
     // Derived 類(lèi)類(lèi)型, 可以使用指針pd訪問(wèn)Derived類(lèi)的成員
     cout << "& = " << pd << endl;
     pd->print();
   }
   else
   {
     Child* pc = dynamic_cast<Child*>(pb);
     
     if(pc != NULL)
     {
       // Child 類(lèi)類(lèi)型, 可以使用指針pc訪問(wèn)Child類(lèi)的成員
       cout << "& = " << pc << endl;
       cout << "I'm a Child. " << endl;
     }
     else
     {
       // Base 類(lèi)類(lèi)型, 可以使用指針pb訪問(wèn)Base類(lèi)的成員
       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;
 }
 /**
 * 運(yùn)行結(jié)果:
 * & = 0
 * I'm a Base. 
 * & = 0x7ffccf0dd860
 * I'm a Derived.
 * & = 0x7ffccf0dd870
 * I'm a Child.
 */

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

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

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

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

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

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

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

  4)typeid 使用時(shí)直接指定對(duì)象或者類(lèi)型。

  5)typeid 在不同的編譯器內(nèi)部實(shí)現(xiàn)是不同的;

int i = 0;

const type_info& tiv = typeid(i); // 將 i 的類(lèi)型信息放到 type_info 中去;
const type_info& tii = typeid(int);

cout << (tiv == tii) << endl; // 1

利用 typeid 實(shí)現(xiàn)類(lèi)型識(shí)別

 #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;
 }
 /**
  * 運(yùn)行結(jié)果:
  * 4Base
  * 7Derived
  * 5Child
  * i
  * c
  * & = 0x7ffcbd4d6280
  * I'm a Base. 
  * 4Base
  * & = 0x7ffcbd4d6290
  * I'm a Derived.
  * 7Derived
 * & = 0x7ffcbd4d62a0
 * I'm a Child.
 * 5Child
 */ 

看完了這篇文章,相信你對(duì)c++中類(lèi)型識(shí)別作用是什么有了一定的了解,想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI