日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++超詳細講解強制類型轉換的用法_C 語言

作者:loongknown ? 更新時間: 2022-08-11 編程語言

static_cast

static_cast<type-id>(expression)

expression 轉換為 type-id 類型。static_cast 是靜態類型轉換,發生在編譯期。這種轉換不會進行運行時的動態檢查(RTTI),因而這種轉換可能是不安全的。static_cast 典型應用場景如下:

1. 類的層級結構中,基類和子類之間指針或者引用的轉換。

上行轉換(Upcasting),也即子類像基類方向轉換,是安全的。

下行轉換(Downcasting),也即基類向子類方向轉換,是不安全的,需要程序員自行保證安全轉換。

下面舉例說明:

class A {
public:
  virtual void func() {
    std::cout << "A::func()" << std::endl;
  } 
};
class B : public A {
public:
  virtual void func() {
    std::cout << "B::func()" << std::endl;
  }
  void print() {
    std::cout << "B::print()" << std::endl;
  }
};

對于上行轉換,肯定是安全的。

  B* pb = new B();
  A* pa = static_cast<A*>(pa);
  pa->func();

對于下行轉換:

  A* pa = new B();
  B* pb = static_cast<B*>(pa);
  pb->print();

這里,A* pa = new B();,由于 C++ 的多態的支持,可以使用基類指針指向子類。這里的轉換是安全的,因為 pa 初始化就指向的就是 B。而下面的轉換則是不安全的:

  A* pa = new A();
  B* pb = static_cast<B*>(pa);
  pb->print();

此外,對于兩個不存在繼承關系的兩個類之間轉換,總是失敗的,編譯器報錯:

#include <iostream>
class A {
    virtual void func(){}
};
class B {
    virtual void func(){}
};
int main(){
    A* pa = new A();
    B* pb = static_cast<B*>(pa); 
    return 0;
}

2. 基本數據類型間的轉換。這種轉換也是不安全的,需要程序員自行保證安全轉換。 例如 intshort,直接高位截斷;而 shortint 則高位根據符號位填充。兩種不同類型指針間相互轉換是相當危險的,例如 int*float*。將 int 轉換為指針類型也是危險的轉換,例如 float* p = static_cast<float*>(0X2edf);

3. 將 void 類型轉換為其他類型的指針。 顯然這種轉換也是不安全的,需要程序員自行保證安全轉換。

4. 把其他類型轉換為 void 類型。

有轉換構造函數或者類型轉換函數的類與其它類型之間的轉換。例如:

#include <iostream>
class Point{
public:
    Point(double x, double y): m_x(x), m_y(y){ }
    Point(double& x): m_x(x), m_y(1.1){ }
public:
    operator double() const { return m_x; }  //類型轉換函數
    void print() {
        std::cout << "m_x: " << m_x << "  m_y: " << m_y << std::endl;
    }
private:
    double m_x;
    double m_y;
};
int main() {
    Point p1(12.5, 23.8);
    double x= static_cast<double>(p1);
    // std::cout << x << std::endl;
    Point p2 = static_cast<Point>(x);
    // p2.print();
    return 0;
}

dynamic_cast

dynamic_cast<type-id>(expression)

expression 轉換為 type-id 類型,type-id 必須是類的指針、類的引用或者是 void *;如果 type-id 是指針類型,那么 expression 也必須是一個指針;如果 type-id 是一個引用,那么 expression 也必須是一個引用。

dynamic_cast 提供了運行時的檢查。對于指針類型,在運行時會檢查 expression 是否真正的指向一個 type-id 類型的對象,如果是,則能進行正確的轉換;否則返回 nullptr。對于引用類型,若是無效轉換,則在運行時會拋出異常 std::bad_cast

T1 obj;
T2* pObj = dynamic_cast<T2*>(&obj);    // 無效轉換返回 nullptr
T2& refObj = dynamic_cast<T2&>(obj);   // 無效轉換拋出 bad_cast 異常

上行轉換:其實和 static_cast 是一樣的,一般肯定能成功。例如前面用到的例子:

// A->B
B* pb = new B();
A* pa = static_cast<A*>(pa);  

但是,下面這種繼承關系會轉換失敗:

#include <iostream>
/*    A
     / \
    V  V
    B  C
     \/
     v
     D   */
class A {
    virtual void func(){}
};
class B : public A {
    void func(){}
};
class C : public A {
    void func(){}
};
class D : public B, public C {
    void func(){}
};
int main(){
    D* pd = new D();
    A* pa = dynamic_cast<A*>(pd);
    return 0;
}

上面這個例子,雖然也是上行轉換,但是存在兩條路徑,在 B 和 C 都繼承于 A,并且有虛函數實現,上行轉換不知道從哪條路徑進行轉換。下面的寫法則沒問題:

  D* pd = new D();
  B* pb = dynamic_cast<B*>(pd);
  A* pa = dynamic_cast<A*>(pb);

下行轉換:看個例子。

#include <iostream>
class A {
    virtual void func(){}
};
class B : public A {
    void func(){}
};
int main(){
    A* pa1 = new B();
    A* pa2 = new A();
    B *pb1 = dynamic_cast<B*>(pa1); // ok
    B *pb2 = dynamic_cast<B*>(pa2); // pb2 is a nullptr!
    return 0;
}

其實 dynamic_cast 本質只支持上行轉換,只會沿著繼承鏈向上遍歷,找到目標類型則轉換成功,否則失敗。dynamic_cast 看似支持下行轉換,這都是多態的緣故。上面的例子,pa1 雖然類型是 A,但實際指向 B,沿著 B 向上可以找到 B,因為第一個轉換可以成功。而 pa2 指向 A,沿著 A 向上找不到 B 類型,因而轉換失敗。

因而在有繼承關系的類的轉換時候, static_cast 轉換總是成功的, dynamic_cast 顯然比 static_cast 更加安全。

const_cast

const_cast 用來去掉表達式的 const 修飾或 volatile 修飾,也就是將 constvolatile 類型轉換為非 const 或 非 volatile 類型。

#include <iostream>
int main(){
    const int n = 111;
    int *p = const_cast<int*>(&n);
    *p = 222;
    std::cout<< "n = " << n << std::endl;
    std::cout<< "*p = " << *p << std::endl;
    return 0;
}

這里需要注意:按照正常理解,n 的打印值應該是 222。但是,由于編譯器的常量傳播優化,std::cout<< "n = " << n << std::endl; 會被編譯器替換成類似 std::cout<< "n = " << 111 << std::endl; 的語義。

reinterpret_cast

reinterpret_cast 轉換直接對二進制位按照目標類型重新解釋,非常粗暴,所以風險很高,慎重使用。

#include <iostream>
int main(){
    char str[]="hello world!";
    float *p = reinterpret_cast<float*>(str);
    std::cout << *p << std::endl;  // 1.14314e+27
    return 0;
}

原文鏈接:https://blog.csdn.net/Dong_HFUT/article/details/125343034

欄目分類
最近更新