在C++中,dynamic_cast和static_cast都是用來轉型的操作符,兩者不合理的運用可能會導致在編譯期合法的類型轉換操作卻在運行期也會引發錯誤,當轉型操作涉及到對象指針或引用時,更易發生錯誤。 這兩者又有什么區別呢?
1、dynamic_cast操作符會在運行期對可疑的轉型操作進行安全檢查,而static_cast操作符不會進行安全檢查;
2、dynamic_cast僅對多態有效(轉型的源類型必須是多態,但與轉型的目標類型是否多態無關),而static_cast可施加與任何類型;
3、從派生類到基類的 dynamic_cast 可以進行,這稱為向上轉型;
4、從基類到派生類的 dynamic_cast 不能進行,稱為向下轉型;
5、有繼承關系,派生類可通過dynamic_cast向基類轉換;
6、沒有繼承關系,不能通過dynamic_cast互換;
使用方式:
dynamic_cast<T*>ptr、static_cast<T*>ptr;
dynamic_cast<T&>p、static_cast<T*>p;
下面用一些簡單的代碼來說明關於轉型的一些知識點:
一個基類指針不經過明確的轉型操作,就能指向基類對象或派生類對象;反過來,一個派生類指針指向基類對象是一種不明智的做法。
1 class B 2 { 3 ... 4 }; 5 class D : public B 6 { 7 ... 8 }; 9 int main( ) 10 { 11 D* p; 12 p = new B(); // error 13 p = static_cast<D*>(new B()); // 合法,但可能會造成難以跟蹤的運行錯誤 14 }
再看下面一段代碼:
1 class B 2 { 3 public: 4 virtual void f() { cout<< "f()" <<endl; } 5 }; 6 class D : public B 7 { 8 public: 9 void m(){cout<< "m()" <<endl;} 10 }; 11 int main() 12 { 13 D* p = static_cast<D*>(new B); 14 p -> m(); // ... 15 return 0; 16 }
其中p->m()編譯能通過,但運行出錯。因為P實際指向一個B的對象,而B沒有成員函數m,這種轉型不安全(在VS2010中,可正確運行,輸出:m())。
C++提供的dynamic_cast操作符可以在運行期檢測某個轉型動作是否安全。dynamic_cast和static_cast有同樣的語法,不過dynamic_cast僅對多態類型有效。
1 class C 2 { 3 // C類中無虛函數 4 }; 5 class T 6 { 7 }; 8 int main( ) 9 { 10 T* p = dynamic_cast<T*>(new C()); // error,僅對多態類型有效 11 return 0; 12 }
注意:dynamic_cast操作正確的前提是——轉型的源類型必須是多態的, 但與轉型的目標類型是否多態無關。 在<>中指定的dynamic_cast的目的類型必須是一個指針或引用。
看一個正確的用法:
1 class B 2 { 3 public: 4 virtual void f() {cout << "f()" << endl;} 5 }; 6 class D:public B 7 { 8 public: 9 void m() {cout << "m()" << endl;} 10 }; 11 int main() 12 { 13 D* p = dynamic_cast<D*>(new B()); // 能夠判斷轉型是否安全,如果安全,則返回B對象的地址,否則返回NULL。本例返回NULL。 14 if (p) 15 { 16 p -> m(); 17 } 18 else 19 { 20 cout << “Error\n"; 21 } 22 return 0; 23 }
若有不對或不全的歡迎指正和補充——