程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> 深刻解析C++中的靜態類型轉換與靜態類型轉換運算符

深刻解析C++中的靜態類型轉換與靜態類型轉換運算符

編輯:關於C++

深刻解析C++中的靜態類型轉換與靜態類型轉換運算符。本站提示廣大學習愛好者:(深刻解析C++中的靜態類型轉換與靜態類型轉換運算符)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻解析C++中的靜態類型轉換與靜態類型轉換運算符正文


dynamic_cast 運算符
將操作數 expression 轉換成類型為type-id 的對象。
語法

dynamic_cast < type-id > ( expression )

備注
type-id 必需是一個指針或援用到之前已界說的類類型的援用或“指向 void 的指針”。假如 type-id 是指針,則expression 的類型必需是指針,假如 type-id 是援用,則為左值。
有關靜態和靜態強迫轉換之間差別的描寫,和各在甚麼情形下合適應用,請拜見 static_cast。
在托管代碼中的 dynamic_cast的行動中有兩個嚴重更改。
為指針的dynamic_cast 對指向裝箱的列舉的基本類型的指針將在運轉時掉敗,則前往 0 而不是已轉換的指針。
dynamic_cast 將不再激發一個異常,當 type-id 是指向值類型的外部指針,則轉換在運轉時掉敗。該轉換將前往 0 指導運轉值而不是激發。
假如 type-id 是指向 expression的明白的可拜訪的直接或直接基類的指針,則成果是指向 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
}

此轉換類型稱為“向上轉換”,由於它將在類條理構造上的指針,從派生的類移到該類派生的類。向上轉換是一種隱式轉換。
假如 type-id 為 void*,則做運轉時停止檢討肯定 expression的現實類型。成果是指向 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*,則做運轉時停止檢討以肯定能否由 expression 指向的對象可以轉換為由 type-id指向的類型。
假如 expression 類型是 type-id類型的基類,則做運轉時檢討來看能否 expression 確切指向 type-id類型的完全對象。假如為 true,則成果是指向 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
}

此轉換類型稱為“向下轉換”,由於它將在類條理構造下的指針,從給定的類移到該類派生的類。
關於多重繼續,引入多義性的能夠性。斟酌下圖中顯示的類條理構造。
關於 CLR 類型,假如轉換可以隱式履行,則 dynamic_cast 成果為 no-op,假如轉換掉敗,則 MSIL isinst 指令將履行靜態檢討並前往 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);
}

顯示多重繼續的類條理構造
顯示多繼續的類條理構造
指向類型 D 對象的指針可以平安地強迫轉換為 B 或 C。然則,假如 D 強迫轉換為指向 A 對象的指針,會招致 A 的哪一個實例?這將招致不明白的強迫轉換毛病。若要防止此成績,可以履行兩個明白的轉換。例如:

// 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
}

當應用虛擬基類時,其他多義性成績會被引入。斟酌下圖中顯示的類條理構造。

顯示虛擬基類的類條理構造
在此條理構造中,A 是虛擬基類。關於虛擬基類的界說。給定一個 E 類實例和一個指向 A 子對象的指針,指向 B 指針的 dynamic_cast 將掉敗於多義性。必需先將強迫轉換回完全 E 對象,然後以明白的方法反向沿條理構造,達到准確的 B 對象。
斟酌下圖中顯示的類條理構造。

給定一個 E 類型的對象和一個指向 D 子對象的指針,從 D 子對象定位到最左邊的 A 子對象,可停止三個轉換。可以從 D 指針到 E 指針履行 dynamic_cast 轉換,然後從 E 到 B 履行轉換(dynamic_cast 或隱式轉換),最初從 B 到 A 履行隱式轉換。例如:

// 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 運算符還可使用履行 “互相轉換”。應用統一個類條理構造能夠停止指針轉換,例如: 從B 子對象轉換到D子對象(只需全部對象是類轉換型E。
斟酌互相轉換,現實上從指針轉換到 D 到指針到最左邊的 A 子對象只需兩個步調。可以從 D 到 B 履行互相轉換,然後從 B 到 A 履行隱式轉換。例如:

// 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 指針值轉換到目的類型的 null 指針值。
當您應用 dynamic_cast < type-id > ( expression )時,假如expression沒法平安地轉換成類型 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
}

指針類型的非限制轉換的值是 null 指針。援用類型的非限制轉換會激發 bad_cast 異常。   假如 expression 不指向也不援用有用的對象,則__non_rtti_object 異常激發。
有關異常 __non_rtti_object 的說明,請拜見 typeid。
以下示例創立基類(構造 A)指針,為一個對象(構造 C)。這和在該情形是虛函數,啟用運轉時多態性。
該示例也在條理構造中挪用非虛函數。

// 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 運算符
僅依據表達式中存在的類型,將 expression 轉換為 type-id, 類型。
語法

static_cast <type-id> ( expression ) 

備注
在尺度 C++ 中,不停止運轉時類型檢討來贊助確保轉換的平安。在 C++/CX 中,將履行編譯時和運轉時檢討。
static_cast 運算符可用於將指向基類的指針轉換為指向派生類的指針等操作。此類轉換並不是一直平安。
平日應用 static_cast 轉換數值數據類型,例如將列舉型轉換為整型或將整型轉換為浮點型,並且你能肯定介入轉換的數據類型。 static_cast 轉換平安性不如 dynamic_cast 轉換,由於 static_cast 不履行運轉時類型檢討,而 dynamic_cast 履行該檢討。對不明白的指針的 dynamic_cast 將掉敗,而 static_cast 的前往成果看似沒有成績,這是風險的。雖然 dynamic_cast 轉換加倍平安,然則 dynamic_cast 只實用於指針或援用,並且運轉時類型檢討也是一項開支。
鄙人面的示例中,由於 D 能夠有不在 B 內的字段和辦法,所以行 D* pd2 = static_cast<D*>(pb); 不平安。然則,由於 D 一直包括一切 B,所以行 B* pb2 = static_cast<B*>(pd); 是平安的轉換。

// 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 轉換不履行運轉時檢討。由 pb 指向的對象能夠不是 D 類型的對象,在這類情形下應用 *pd2 會是災害性的。例如,挪用 D 類(而非 B 類)的成員函數能夠會招致拜訪抵觸。
dynamic_cast 和 static_cast 運算符可以在全部類條理構造中挪動指針。但是,static_cast 完整依附於轉換語句供給的信息,是以能夠不平安。例如:

// 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 可以反向履行隱式轉換,而在這類情形下成果是不肯定的。這須要法式員來驗證 static_cast 轉換的成果能否平安。
該行動也實用於類之外的類型。例如,static_cast 可用於將 int 轉換為 char。然則,獲得的 char 能夠沒有足夠的位來保留全部 int 值。異樣,這須要法式員來驗證 static_cast 轉換的成果能否平安。
static_cast 運算符還可用於履行任何隱式轉換,包含尺度轉換和用戶界說的轉換。例如:

// 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 運算符可以將整數值顯式轉換為列舉類型。假如整型值不在列舉值的規模內,生成的列舉值是不肯定的。
static_cast 運算符將 null 指針值轉換為目的類型的 null 指針值。
任何表達式都可以經由過程 static_cast 運算符顯式轉換為 void 類型。目的 void 類型可以選擇性地包括 const、volatile 或 __unaligned 特征。
static_cast 運算符沒法轉換失落 const、volatile 或 __unaligned 特征。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved