最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

深入解析C++中的動態(tài)類型轉(zhuǎn)換與靜態(tài)類型轉(zhuǎn)換運算符

 更新時間:2016年01月15日 15:19:33   投稿:goldensun  
這篇文章主要介紹了C++中的動態(tài)類型轉(zhuǎn)換與靜態(tài)類型轉(zhuǎn)換運算符,即dynamic_cast與static_cast的用法,需要的朋友可以參考下

dynamic_cast 運算符
將操作數(shù) expression 轉(zhuǎn)換成類型為type-id 的對象。
語法

dynamic_cast < type-id > ( expression )

備注
type-id 必須是一個指針或引用到以前已定義的類類型的引用或“指向 void 的指針”。如果 type-id 是指針,則expression 的類型必須是指針,如果 type-id 是引用,則為左值。
有關(guān)靜態(tài)和動態(tài)強制轉(zhuǎn)換之間區(qū)別的描述,以及各在什么情況下適合使用,請參見 static_cast。
在托管代碼中的 dynamic_cast的行為中有兩個重大更改。
為指針的dynamic_cast 對指向裝箱的枚舉的基礎(chǔ)類型的指針將在運行時失敗,則返回 0 而不是已轉(zhuǎn)換的指針。
dynamic_cast 將不再引發(fā)一個異常,當(dāng) type-id 是指向值類型的內(nèi)部指針,則轉(zhuǎn)換在運行時失敗。該轉(zhuǎn)換將返回 0 指示運行值而不是引發(fā)。
如果 type-id 是指向 expression的明確的可訪問的直接或間接基類的指針,則結(jié)果是指向 type-id 類型的唯一子對象的指針。例如:

// dynamic_cast_1.cpp
// compile with: /c
class B { };
class C : public B { };
class D : public C { };

void f(D* pd) {
  C* pc = dynamic_cast<C*>(pd);  // ok: C is a direct base class
                  // pc points to C subobject of pd 
  B* pb = dynamic_cast<B*>(pd);  // ok: B is an indirect base class
                  // pb points to B subobject of pd
}

此轉(zhuǎn)換類型稱為“向上轉(zhuǎn)換”,因為它將在類層次結(jié)構(gòu)上的指針,從派生的類移到該類派生的類。向上轉(zhuǎn)換是一種隱式轉(zhuǎn)換。
如果 type-id 為 void*,則做運行時進(jìn)行檢查確定 expression的實際類型。結(jié)果是指向 by expression 的完整的對象的指針。例如:

// dynamic_cast_2.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
  A* pa = new A;
  B* pb = new B;
  void* pv = dynamic_cast<void*>(pa);
  // pv now points to an object of type A

  pv = dynamic_cast<void*>(pb);
  // pv now points to an object of type B
}

如果 type-id 不是 void*,則做運行時進(jìn)行檢查以確定是否由 expression 指向的對象可以轉(zhuǎn)換為由 type-id指向的類型。
如果 expression 類型是 type-id類型的基類,則做運行時檢查來看是否 expression 確實指向 type-id類型的完整對象。如果為 true,則結(jié)果是指向 type-id類型的完整對象的指針。例如:

// dynamic_cast_3.cpp
// compile with: /c /GR
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 points to a B not a D
}

此轉(zhuǎn)換類型稱為“向下轉(zhuǎn)換”,因為它將在類層次結(jié)構(gòu)下的指針,從給定的類移到該類派生的類。
對于多重繼承,引入多義性的可能性??紤]下圖中顯示的類層次結(jié)構(gòu)。
對于 CLR 類型,如果轉(zhuǎn)換可以隱式執(zhí)行,則 dynamic_cast 結(jié)果為 no-op,如果轉(zhuǎn)換失敗,則 MSIL isinst 指令將執(zhí)行動態(tài)檢查并返回 nullptr。
以下示例使用 dynamic_cast 以確定一個類是否為特殊類型的實例:

// dynamic_cast_clr.cpp
// compile with: /clr
using namespace System;

void PrintObjectType( Object^o ) {
  if( dynamic_cast<String^>(o) )
   Console::WriteLine("Object is a String");
  else if( dynamic_cast<int^>(o) )
   Console::WriteLine("Object is an int");
}

int main() {
  Object^o1 = "hello";
  Object^o2 = 10;

  PrintObjectType(o1);
  PrintObjectType(o2);
}

顯示多重繼承的類層次結(jié)構(gòu)
顯示多繼承的類層次結(jié)構(gòu)
指向類型 D 對象的指針可以安全地強制轉(zhuǎn)換為 B 或 C。但是,如果 D 強制轉(zhuǎn)換為指向 A 對象的指針,會導(dǎo)致 A 的哪個實例?這將導(dǎo)致不明確的強制轉(zhuǎn)換錯誤。若要避免此問題,可以執(zhí)行兩個明確的轉(zhuǎn)換。例如:

// dynamic_cast_4.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};
class D : public B {virtual void f();};

void f() {
  D* pd = new D;
  B* pb = dynamic_cast<B*>(pd);  // first cast to B
  A* pa2 = dynamic_cast<A*>(pb);  // ok: unambiguous
}

當(dāng)使用虛擬基類時,其他多義性問題會被引入??紤]下圖中顯示的類層次結(jié)構(gòu)。

2016115151645156.jpeg (221×54)

顯示虛擬基類的類層次結(jié)構(gòu)
在此層次結(jié)構(gòu)中,A 是虛擬基類。對于虛擬基類的定義。給定一個 E 類實例和一個指向 A 子對象的指針,指向 B 指針的 dynamic_cast 將失敗于多義性。必須先將強制轉(zhuǎn)換回完整 E 對象,然后以明確的方式反向沿層次結(jié)構(gòu),到達(dá)正確的 B 對象。
考慮下圖中顯示的類層次結(jié)構(gòu)。

2016115151749363.jpeg (339×60)

給定一個 E 類型的對象和一個指向 D 子對象的指針,從 D 子對象定位到最左側(cè)的 A 子對象,可進(jìn)行三個轉(zhuǎn)換??梢詮?D 指針到 E 指針執(zhí)行 dynamic_cast 轉(zhuǎn)換,然后從 E 到 B 執(zhí)行轉(zhuǎn)換(dynamic_cast 或隱式轉(zhuǎn)換),最后從 B 到 A 執(zhí)行隱式轉(zhuǎn)換。例如:

// dynamic_cast_5.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
  E* pe = dynamic_cast<E*>(pd);
  B* pb = pe;  // upcast, implicit conversion
  A* pa = pb;  // upcast, implicit conversion
}

dynamic_cast 運算符還可以使用執(zhí)行 “相互轉(zhuǎn)換”。使用同一個類層次結(jié)構(gòu)可能進(jìn)行指針轉(zhuǎn)換,例如: 從B 子對象轉(zhuǎn)換到D子對象(只要整個對象是類轉(zhuǎn)換型E。
考慮相互轉(zhuǎn)換,實際上從指針轉(zhuǎn)換到 D 到指針到最左側(cè)的 A 子對象只要兩個步驟??梢詮?D 到 B 執(zhí)行相互轉(zhuǎn)換,然后從 B 到 A 執(zhí)行隱式轉(zhuǎn)換。例如:

// dynamic_cast_6.cpp
// compile with: /c /GR
class A {virtual void f();};
class B : public A {virtual void f();};
class C : public A { };
class D {virtual void f();};
class E : public B, public C, public D {virtual void f();};

void f(D* pd) {
  B* pb = dynamic_cast<B*>(pd);  // cross cast
  A* pa = pb;  // upcast, implicit conversion
}

通過 dynamic_cast 將 null 指針值轉(zhuǎn)換到目標(biāo)類型的 null 指針值。
當(dāng)您使用 dynamic_cast < type-id > ( expression )時,如果expression無法安全地轉(zhuǎn)換成類型 type-id,則運行時檢查會引起變換失敗。例如:

// dynamic_cast_7.cpp
// compile with: /c /GR
class A {virtual void f();};
class B {virtual void f();};

void f() {
  A* pa = new A;
  B* pb = dynamic_cast<B*>(pa);  // fails at runtime, not safe;
  // B not derived from A
}

指針類型的非限定轉(zhuǎn)換的值是 null 指針。引用類型的非限定轉(zhuǎn)換會引發(fā) bad_cast 異常。   如果 expression 不指向也不引用有效的對象,則__non_rtti_object 異常引發(fā)。
有關(guān)異常 __non_rtti_object 的解釋,請參見 typeid。
以下示例創(chuàng)建基類(結(jié)構(gòu) A)指針,為一個對象(結(jié)構(gòu) C)。這以及在該情況是虛函數(shù),啟用運行時多態(tài)性。
該示例也在層次結(jié)構(gòu)中調(diào)用非虛函數(shù)。

// dynamic_cast_8.cpp
// compile with: /GR /EHsc
#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);
}

輸出:

in C
test2 in B
in GlobalTest

static_cast 運算符
僅根據(jù)表達(dá)式中存在的類型,將 expression 轉(zhuǎn)換為 type-id, 類型。
語法

static_cast <type-id> ( expression ) 

備注
在標(biāo)準(zhǔn) C++ 中,不進(jìn)行運行時類型檢查來幫助確保轉(zhuǎn)換的安全。在 C++/CX 中,將執(zhí)行編譯時和運行時檢查。
static_cast 運算符可用于將指向基類的指針轉(zhuǎn)換為指向派生類的指針等操作。此類轉(zhuǎn)換并非始終安全。
通常使用 static_cast 轉(zhuǎn)換數(shù)值數(shù)據(jù)類型,例如將枚舉型轉(zhuǎn)換為整型或?qū)⒄娃D(zhuǎn)換為浮點型,而且你能確定參與轉(zhuǎn)換的數(shù)據(jù)類型。 static_cast 轉(zhuǎn)換安全性不如 dynamic_cast 轉(zhuǎn)換,因為 static_cast 不執(zhí)行運行時類型檢查,而 dynamic_cast 執(zhí)行該檢查。對不明確的指針的 dynamic_cast 將失敗,而 static_cast 的返回結(jié)果看似沒有問題,這是危險的。盡管 dynamic_cast 轉(zhuǎn)換更加安全,但是 dynamic_cast 只適用于指針或引用,而且運行時類型檢查也是一項開銷。
在下面的示例中,因為 D 可能有不在 B 內(nèi)的字段和方法,所以行 D* pd2 = static_cast<D*>(pb); 不安全。但是,因為 D 始終包含所有 B,所以行 B* pb2 = static_cast<B*>(pd); 是安全的轉(zhuǎn)換。

// static_cast_Operator.cpp
// compile with: /LD
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.
}

與 dynamic_cast 不同,pb 的 static_cast 轉(zhuǎn)換不執(zhí)行運行時檢查。由 pb 指向的對象可能不是 D 類型的對象,在這種情況下使用 *pd2 會是災(zāi)難性的。例如,調(diào)用 D 類(而非 B 類)的成員函數(shù)可能會導(dǎo)致訪問沖突。
dynamic_cast 和 static_cast 運算符可以在整個類層次結(jié)構(gòu)中移動指針。然而,static_cast 完全依賴于轉(zhuǎn)換語句提供的信息,因此可能不安全。例如:

// static_cast_Operator_2.cpp
// compile with: /LD /GR
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 確實指向 D 類型的對象,則 pd1 和 pd2 將獲取相同的值。如果 pb == 0,它們也將獲取相同的值。
如果 pb 指向 B 類型的對象,而非指向完整的 D 類,則 dynamic_cast 足以判斷返回零。但是,static_cast 依賴于程序員的斷言,即 pb 指向 D 類型的對象,因而只是返回指向那個假定的 D 對象的指針。
因此,static_cast 可以反向執(zhí)行隱式轉(zhuǎn)換,而在這種情況下結(jié)果是不確定的。這需要程序員來驗證 static_cast 轉(zhuǎn)換的結(jié)果是否安全。
該行為也適用于類以外的類型。例如,static_cast 可用于將 int 轉(zhuǎn)換為 char。但是,得到的 char 可能沒有足夠的位來保存整個 int 值。同樣,這需要程序員來驗證 static_cast 轉(zhuǎn)換的結(jié)果是否安全。
static_cast 運算符還可用于執(zhí)行任何隱式轉(zhuǎn)換,包括標(biāo)準(zhǔn)轉(zhuǎn)換和用戶定義的轉(zhuǎn)換。例如:

// static_cast_Operator_3.cpp
// compile with: /LD /GR
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);
}

static_cast 運算符可以將整數(shù)值顯式轉(zhuǎn)換為枚舉類型。如果整型值不在枚舉值的范圍內(nèi),生成的枚舉值是不確定的。
static_cast 運算符將 null 指針值轉(zhuǎn)換為目標(biāo)類型的 null 指針值。
任何表達(dá)式都可以通過 static_cast 運算符顯式轉(zhuǎn)換為 void 類型。目標(biāo) void 類型可以選擇性地包含 const、volatile 或 __unaligned 特性。
static_cast 運算符無法轉(zhuǎn)換掉 const、volatile 或 __unaligned 特性。

相關(guān)文章

  • C++線程間的互斥和通信場景分析

    C++線程間的互斥和通信場景分析

    很多朋友對C++線程間的互斥和通信知識掌握不是多牢靠,今天小編通過模擬車站賣票應(yīng)用場景給大家詳細(xì)解析C++線程間的互斥和通信知識,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • C++淺析內(nèi)聯(lián)函數(shù)的使用

    C++淺析內(nèi)聯(lián)函數(shù)的使用

    為了消除函數(shù)調(diào)用的時空開銷,C++ 提供一種提高效率的方法,即在編譯時將函數(shù)調(diào)用處用函數(shù)體替換,類似于C語言中的宏展開。這種在函數(shù)調(diào)用處直接嵌入函數(shù)體的函數(shù)稱為內(nèi)聯(lián)函數(shù)(Inline Function),又稱內(nèi)嵌函數(shù)或者內(nèi)置函數(shù)
    2022-05-05
  • 關(guān)于C++的.cpp文件運行全過程

    關(guān)于C++的.cpp文件運行全過程

    這篇文章主要介紹了C++的.cpp文件運行全過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C++ 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)兩個棧實現(xiàn)一個隊列

    C++ 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)兩個棧實現(xiàn)一個隊列

    這篇文章主要介紹了詳解C++ 數(shù)據(jù)結(jié)構(gòu)實現(xiàn)兩個棧實現(xiàn)一個隊列的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • C++學(xué)習(xí)之指針的使用詳解

    C++學(xué)習(xí)之指針的使用詳解

    這篇文章主要為大家詳細(xì)介紹了C++中指針的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們的學(xué)習(xí)或工作有一定的價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • Linux下使用C/C++進(jìn)行UDP網(wǎng)絡(luò)編程詳解

    Linux下使用C/C++進(jìn)行UDP網(wǎng)絡(luò)編程詳解

    UDP 是User Datagram Protocol 的簡稱,中文名是用戶數(shù)據(jù)報協(xié)議,是一種無連接、不可靠的協(xié)議,本文主要介紹了如何在Linux下使用C/C++進(jìn)行UDP網(wǎng)絡(luò)編程,有需要的可以了解下
    2024-10-10
  • Qt項目實戰(zhàn)之實現(xiàn)MP3音樂播放器

    Qt項目實戰(zhàn)之實現(xiàn)MP3音樂播放器

    這篇文章主要為大家詳細(xì)介紹了如何利用Qt實現(xiàn)MP3音樂播放器,文中的示例代碼講解詳細(xì),具有一定的參考價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • Microsoft Visual C++ 安裝失敗 0x80070666的問題解決

    Microsoft Visual C++ 安裝失敗 0x80070666的問題解

    本文主要介紹了Microsoft Visual C++ 安裝失敗 0x80070666的問題解決,錯誤可能由已安裝其他VisualC++版本、VisualC++安裝異常、Windows更新計劃安裝同一VisualC++包等原因引起,下面就來介紹一下解決方案,感興趣的可以了解一下
    2025-03-03
  • 如何高效移除C++關(guān)聯(lián)容器中的元素

    如何高效移除C++關(guān)聯(lián)容器中的元素

    關(guān)聯(lián)容器和順序容器有著很大不同,關(guān)聯(lián)容器中的元素是按照關(guān)鍵字來保存和訪問的,而順序容器中的元素是按它們在容器中的位置來順序保存和訪問的,本文介紹了如何高效移除C++關(guān)聯(lián)容器中的元素的方法,需要的朋友可以參考下
    2025-04-04
  • typedef和#define用法區(qū)別總結(jié)

    typedef和#define用法區(qū)別總結(jié)

    在C還是C++代碼中,typedef都使用的很多,在C代碼中尤其多,typedef與#define有些相似,其實是不同的,特別是在一些復(fù)雜的用法上,下面這篇文章主要給大家介紹了關(guān)于typedef和#define用法區(qū)別總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2023-06-06

最新評論

湛江市| 东兰县| 贡嘎县| 上林县| 荆门市| 睢宁县| 江山市| 寻甸| 依兰县| 延津县| 焉耆| 金堂县| 遂溪县| 都江堰市| 牟定县| 股票| 忻州市| 英德市| 台江县| 刚察县| 开原市| 蓬溪县| 饶阳县| 洛阳市| 怀集县| 青州市| 莆田市| 雅江县| 新源县| 通榆县| 延津县| 青铜峡市| 吉水县| 新丰县| 波密县| 自贡市| 盐山县| 宜宾县| 德化县| 分宜县| 额济纳旗|