標籤:int idt enter 期望 不能 end isp 原則 space
類型識別:
為什麼引入類型識別呢?因為物件導向中有一個非常重要的原則就是賦值相容性原則,就是子類對象完全可以當成父類對象使用。
當我們拿到指標p,我們知道它到底指向子類還是父類對象嗎?
p的靜態類型是Base,本意是期望指向Base對象,但是由於賦值相容性,指標有可能指向子類對象,子類對象在這裡是動態類型。
想要安全的轉換就要得到b實際指向的動態類型,我們需要提前判斷動態類型是什麼。
C++中如何得到動態類型呢?
樣本程式:
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Base 7 { 8 public: 9 virtual string type()10 {11 return "Base";12 }13 };14 15 class Derived : public Base16 {17 public:18 string type()19 {20 return "Derived";21 }22 23 void printf()24 {25 cout << "I‘m a Derived." << endl;26 }27 };28 29 class Child : public Base30 {31 public:32 string type()33 {34 return "Child";35 }36 };37 38 void test(Base* b)39 {40 /* 危險的轉換方式 */41 // Derived* d = static_cast<Derived*>(b);42 43 if( b->type() == "Derived" )44 {45 Derived* d = static_cast<Derived*>(b);46 47 d->printf();48 }49 50 // cout << dynamic_cast<Derived*>(b) << endl;51 }52 53 54 int main(int argc, char *argv[])55 {56 Base b;57 Derived d;58 Child c;59 60 test(&b);61 test(&d);62 test(&c);63 64 return 0;65 }
運行結果如下:
我們不僅需要知道dynamic_cast轉換是不是成功,還需要知道具體的類型到底是什麼,因此,dynamic_cast在這裡不夠用。
虛函數傳回型別的方式能解決問題,但是不夠好,當我們增加新類時容易和以前的重複或者混淆。
多態解決方案的缺陷:
C++的解決方案:
樣本程式:
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 Base16 {17 public:18 void printf()19 {20 cout << "I‘m a Derived." << endl;21 }22 };23 24 void test(Base* b)25 {26 const type_info& tb = typeid(*b);27 28 cout << tb.name() << endl;29 }30 31 int main(int argc, char *argv[])32 {33 int i = 0;34 35 const type_info& tiv = typeid(i);36 const type_info& tii = typeid(int);37 38 cout << (tiv == tii) << endl;39 40 Base b;41 Derived d;42 43 test(&b);44 test(&d);45 46 return 0;47 }
typeid返回的是對象,這個對象的類型在typeinfo庫中。
BCC中的輸出如下:
可見,typeid在不同系統中的實現時不一樣的,我們不能假設typeid的實現。
小結:
第66課 C++中的類型識別