欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解c++中的類型識別

 更新時間:2020年06月30日 09:17:37   作者:PRO_Z  
這篇文章主要介紹了 詳解c++中的類型識別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

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

(1)類型識別的作用

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

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

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

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

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

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

(2)類型識別的分類

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

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

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

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

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

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

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

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

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

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

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

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

 #include <iostream>
 #include <string>
 
 using namespace std;
 
 class Base
 {
 public:
   enum { ID = 0 };
   
   virtual int type() // 類型虛函數(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這個關(guān)鍵字如果要轉(zhuǎn)換的實際類型和指定的類型不一樣,則會返回NULL。例如當(dāng)指定類型為子類對象時,如果父類指針的動態(tài)類型是這個子類對象時,轉(zhuǎn)換成功,而動態(tài)類型是父類對象或者其他子類對象時,轉(zhuǎn)換失??;

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

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

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

    2.用于引用轉(zhuǎn)換時,轉(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é)果,無法獲取動態(tài)類型的原型
   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;
 }
 /**
 * 運(yùn)行結(jié)果:
 * & = 0
 * I'm a Base. 
 * & = 0x7ffccf0dd860
 * I'm a Derived.
 * & = 0x7ffccf0dd870
 * I'm a Child.
 */

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

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

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

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

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

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

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

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

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

int i = 0;

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

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

利用 typeid 實現(xiàn)類型識別

 #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
 */ 

  結(jié)論:

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

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

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

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

  3)每個派生類的類型名必須唯一;

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

到此這篇關(guān)于 詳解c++中的類型識別的文章就介紹到這了,更多相關(guān)c++ 類型識別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 算法之排列算法與組合算法詳解

    算法之排列算法與組合算法詳解

    這篇文章主要介紹了算法之排列算法與組合算法詳解,本文以字典序法、遞歸法為例講解了排列算法、全組合算法等,需要的朋友可以參考下
    2014-08-08
  • C語言 實現(xiàn)N階乘的程序代碼

    C語言 實現(xiàn)N階乘的程序代碼

    本篇文章是對c語言中實現(xiàn)N階乘的程序代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • JS調(diào)用C++函數(shù)拋出異常及捕捉異常詳解

    JS調(diào)用C++函數(shù)拋出異常及捕捉異常詳解

    這篇文章主要介紹了js調(diào)用C++函數(shù)的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-08-08
  • C/C++ 函數(shù)原理傳參示例詳解

    C/C++ 函數(shù)原理傳參示例詳解

    這篇文章主要為大家介紹了C/C++ 函數(shù)原理傳參示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • C++ 命名空間--namespace總結(jié)

    C++ 命名空間--namespace總結(jié)

    namespace中文意思是命名空間或者叫名字空間,下面這篇文章主要給大家介紹了關(guān)于C++中名稱空間namespace使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起看看吧
    2021-09-09
  • Windows10配置VSCode C++環(huán)境(超詳細(xì),面向小白以及大佬們)

    Windows10配置VSCode C++環(huán)境(超詳細(xì),面向小白以及大佬們)

    這篇文章主要介紹了Windows10配置VSCode C++環(huán)境(超詳細(xì),面向小白以及大佬們),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12
  • C++面試八股文之了解auto關(guān)鍵字

    C++面試八股文之了解auto關(guān)鍵字

    這篇文章主要為大家介紹了C++面試八股文之了解auto關(guān)鍵字問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • VC枚舉串口端口應(yīng)用

    VC枚舉串口端口應(yīng)用

    這篇文章主要介紹了VC枚舉串口端口應(yīng)用,羅列了常見的一些串口端口的應(yīng)用實例,需要的朋友可以參考下
    2014-10-10
  • C++?電話號碼的字母組合功能實現(xiàn)

    C++?電話號碼的字母組合功能實現(xiàn)

    這篇文章主要介紹了C++?電話號碼的字母組合,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-08-08
  • C語言中的字符串?dāng)?shù)據(jù)在C中的存儲方式

    C語言中的字符串?dāng)?shù)據(jù)在C中的存儲方式

    這篇文章主要介紹了C語言中的字符串?dāng)?shù)據(jù)在C中的存儲方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07

最新評論