C++基礎(chǔ)入門篇之強(qiáng)制轉(zhuǎn)換
引言
假設(shè)有基類 A,包含了虛函數(shù) func1,以及有派生類 B,繼承于類 A,派生類 B 中實(shí)現(xiàn)了函數(shù) func1。此時(shí)可以用 A 類型的指針指向 B 類型的對(duì)象,并用 A 類型的指針調(diào)用 B 類型對(duì)象中的函數(shù) func1。這時(shí),就形成了多態(tài)。包含虛函數(shù)的類 A,我們也稱為多態(tài)類。
由于派生類 B 完整包含了 基類 A 的所有定義,將 B 類型的指針轉(zhuǎn)換為 A 類型的指針總是安全的。
而將 A 類型的指針強(qiáng)制轉(zhuǎn)換為 B 類型的指針時(shí),如果 A 類型指針指向的對(duì)象確實(shí)為 B 類型的對(duì)象,那么轉(zhuǎn)換也是安全的。此時(shí),該 B 類型對(duì)象被稱為完整對(duì)象(complete object)。
強(qiáng)制轉(zhuǎn)換有哪些類型?
C++ 包含了以下幾種強(qiáng)制轉(zhuǎn)換運(yùn)算符,這些運(yùn)算符用于消除老式 C 語言轉(zhuǎn)換中的存在的歧義和隱患:
- dynamic_cast
- static_cast
- const_cast
- reinterpret_cast
- safe_cast
本文會(huì)著重介紹如何使用 dynamic_cast 和 static_cast。
提醒:
除非必須,不要使用 const_cast 和 reinterpret_cast,因?yàn)樗鼈兇嬖谝恍├鲜?C 語言轉(zhuǎn)換中的隱患。
dynamic_cast 運(yùn)算符
語法:
dynamic_cast <type-id> (expression)
type-id 必須是一個(gè)指針或者引用,指向/引用已定義的類類型或者 void。如果type-id 是指針,則 expression 必須也為指針類型,如果 type-id 是引用,expression 必須為左值類型。
如果 type-id 是 void*,那么在運(yùn)行時(shí)將檢測(cè) expression 的實(shí)際類型。其結(jié)果返回 expression 指向的完整對(duì)象。
如非需要,現(xiàn)代 C++ 中應(yīng)該避免使用 void 指針,因?yàn)槿菀壮鲥e(cuò)。
下面看些示例,了解 dynamic_cast 的使用方式。
示例1:
class Root { }; class Base : public Root { }; class Derived : public Base { }; void f(Derived* pd) { Base* pb = dynamic_cast<Base*>(pd); // ok: Base is a direct base class // pb points to Base subobject of pd Root* pr = dynamic_cast<Root*>(pd); // ok: Root is an indirect base class // pr points to Root subobject of pd }
示例1 中提到了子對(duì)象(subobject)的概念,注意與子類型進(jìn)行區(qū)分:
- Root 類型包含子類型 Base,Base 類型包含子類型 Derived。
- Derived 對(duì)象包含了 Base 類型的子對(duì)象,Base 類型的子對(duì)象又包含了 Root 類型的子對(duì)象。
再聯(lián)系下前面說的:派生類完整包含了基類的所有定義。
示例2:
class B {virtual void f();}; class D : public B {virtual void f();}; void f() { B* pb = new D; // unclear but ok B* pb2 = new B; D* pd = dynamic_cast<D*>(pb); // ok: pb actually points to a D D* pd2 = dynamic_cast<D*>(pb2); // pb2 was nullptr. }
示例2 中 通過 dynamic_cast 轉(zhuǎn)換為 pd2 時(shí),不會(huì)報(bào)錯(cuò),返回 nullptr。但如果同樣地情況轉(zhuǎn)換的對(duì)象是引用類型,那么運(yùn)行時(shí)會(huì)拋出 std::bad_cast 異常。如果 pb2 指向/引用的對(duì)象無效,同樣也會(huì)拋出異常。
示例3:
#include <stdio.h> #include <iostream> struct A { virtual void test() { printf_s("in A\n"); } }; struct B : A { virtual void test() { printf_s("in B\n"); } void test2() { printf_s("test2 in B\n"); } }; struct C : B { virtual void test() { printf_s("in C\n"); } void test2() { printf_s("test2 in C\n"); } }; void Globaltest(A& a) { try { C &c = dynamic_cast<C&>(a); printf_s("in GlobalTest\n"); } catch(std::bad_cast) { printf_s("Can't cast to C\n"); } } int main() { A *pa = new C; A *pa2 = new B; pa->test(); B * pb = dynamic_cast<B *>(pa); if (pb) pb->test2(); C * pc = dynamic_cast<C *>(pa2); if (pc) pc->test2(); C ConStack; Globaltest(ConStack); // will fail because B knows nothing about C B BonStack; Globaltest(BonStack); } Output: in C test2 in B in GlobalTest Can't cast to C
static_cast 運(yùn)算符
語法:
static_cast <type-id> (expression)
static_cast 通常用于數(shù)值類型轉(zhuǎn)換,例如枚舉和整型,整型和浮點(diǎn)類型的轉(zhuǎn)換。
在標(biāo)準(zhǔn) C++ 中,static_cast 轉(zhuǎn)換沒有運(yùn)行時(shí)檢測(cè)來保證安全性。在 C++/CX 中,則包含了編譯和運(yùn)行時(shí)檢測(cè)。
static_cast 運(yùn)算符能夠用于將基類指針轉(zhuǎn)換為派生類指針,但這樣的轉(zhuǎn)換不總是安全的。
下面還是通過示例進(jìn)行講解。
示例1:
class B {}; class D : public B {}; void f(B* pb, D* pd) { D* pd2 = static_cast<D*>(pb); // Not safe, D can have fields // and methods that are not in B. B* pb2 = static_cast<B*>(pd); // Safe conversion, D always // contains all of B. }
示例1 中 pd2 不為空,當(dāng)用指針 pd2 調(diào)用 B 類型對(duì)象不存在的方法或者成員時(shí)可能會(huì)發(fā)生運(yùn)行時(shí)錯(cuò)誤(比如調(diào)用虛函數(shù))或者返回非預(yù)期的值。
示例2:
typedef unsigned char BYTE; void f() { char ch; int i = 65; float f = 2.5; double dbl; ch = static_cast<char>(i); // int to char dbl = static_cast<double>(f); // float to double i = static_cast<BYTE>(ch); }
示例2 中 static_cast 運(yùn)算符顯示地將內(nèi)置類型進(jìn)行轉(zhuǎn)換。
關(guān)于 static_cast 運(yùn)算符,還有以下幾種使用情況:
- static_cast 能夠顯式的將整型轉(zhuǎn)換為枚舉類型。如果整型值不在枚舉值范圍內(nèi),那么返回的枚舉值是未定義的。
- static_cast 能將任何 expression 顯式地轉(zhuǎn)換為 void 類型。
- static_cast 操作符不會(huì)去除 const,volatile,__unaligned 屬性。
區(qū)分幾種強(qiáng)制轉(zhuǎn)換的使用場(chǎng)景
dynamic_cast 主要用于多態(tài)類型的強(qiáng)制轉(zhuǎn)換,而 static_cast 主要用于非多態(tài)類型的強(qiáng)制轉(zhuǎn)換。
static_cast 轉(zhuǎn)換不像 dynamic_cast 那樣安全。因?yàn)?static_cast 沒有運(yùn)行時(shí)檢測(cè)。通過 dynamic_cast 進(jìn)行轉(zhuǎn)換時(shí),一旦存在歧義,就會(huì)導(dǎo)致失敗,然而 static_cast 會(huì)像沒有錯(cuò)誤發(fā)生一樣返回結(jié)果。盡管 dynamic_cast 更加安全,但 dynamic_cast 僅適用于指針和引用,并且運(yùn)行時(shí)檢測(cè)是需要消耗性能的。
示例:
class B { public: virtual void Test(){} }; class D : public B {}; void f(B* pb) { D* pd1 = dynamic_cast<D*>(pb); D* pd2 = static_cast<D*>(pb); }
如果 pb 實(shí)際指向類型 D 或者 pd == 0,那么 pd1 和 pd2 將獲得相同的值。
如果 pb 實(shí)際指向類型 B,那么 dynamic_cast 會(huì)返回 0。但是 static_cast 依賴于 expression 認(rèn)定 pb 指向 D 類型對(duì)象,于是簡(jiǎn)單的返回 D 類型的指針。
結(jié)果就是,static_cast 轉(zhuǎn)換會(huì)繼續(xù)執(zhí)行,但其返回結(jié)果是未定義的。這就需要調(diào)用者去進(jìn)一步驗(yàn)證轉(zhuǎn)換結(jié)果是有效的。
引用
https://docs.microsoft.com/en-us/cpp/cpp/casting?view=msvc-160
總結(jié)
到此這篇關(guān)于C++基礎(chǔ)入門篇之強(qiáng)制轉(zhuǎn)換的文章就介紹到這了,更多相關(guān)C++強(qiáng)制轉(zhuǎn)換內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++LeetCode數(shù)據(jù)結(jié)構(gòu)基礎(chǔ)詳解
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode數(shù)據(jù)結(jié)構(gòu),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08vscode工程中c_cpp_properties.json文件作用詳細(xì)說明
c_cpp_properties.json是Visual Studio Code的一個(gè)配置文件,用于定義C/C++編譯器的路徑、默認(rèn)包含路徑和預(yù)處理器定義,這篇文章主要給大家介紹了關(guān)于vscode工程中c_cpp_properties.json文件作用詳細(xì)說明的相關(guān)資料,需要的朋友可以參考下2024-08-08C++ 網(wǎng)絡(luò)連通性檢測(cè)的實(shí)現(xiàn)方法
這篇文章主要介紹了C++ 網(wǎng)絡(luò)連通性檢測(cè)的實(shí)現(xiàn)方法的相關(guān)資料,這里提供實(shí)例幫助大家實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-09-09C++結(jié)合OpenCV實(shí)現(xiàn)RRT算法(路徑規(guī)劃算法)
這篇文章主要介紹了C++結(jié)合OpenCV實(shí)現(xiàn)RRT算法,RRT算法整體框架主要分為rand、near、new三點(diǎn)的建立和near與new之間的安全性檢查,需要的朋友可以參考下2022-05-05C++?獲取當(dāng)前正在運(yùn)行函數(shù)的名稱
本文主要介紹了C++獲取當(dāng)前正在運(yùn)行函數(shù)的名稱,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04Opencv2.4.9函數(shù)HoughLinesP分析
這篇文章主要為大家詳細(xì)介紹了Opencv2.4.9函數(shù)HoughLinesP,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01