亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

 更新時間:2022年06月20日 08:37:22   作者:loongknown  
在C++語言中新增了四個關鍵字static_cast、const_cast、reinterpret_cast和dynamic_cast。這四個關鍵字都是用于類型轉換的,類型轉換(type?cast),是高級語言的一個基本語法。它被實現(xiàn)為一個特殊的運算符,以小括號內加上類型名來表示,接下來讓我們一起來詳細了解

static_cast

static_cast<type-id>(expression)

expression 轉換為 type-id 類型。static_cast 是靜態(tài)類型轉換,發(fā)生在編譯期。這種轉換不會進行運行時的動態(tài)檢查(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++ 的多態(tài)的支持,可以使用基類指針指向子類。這里的轉換是安全的,因為 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. 基本數(shù)據類型間的轉換。這種轉換也是不安全的,需要程序員自行保證安全轉換。 例如 intshort,直接高位截斷;而 shortint 則高位根據符號位填充。兩種不同類型指針間相互轉換是相當危險的,例如 int*float*。將 int 轉換為指針類型也是危險的轉換,例如 float* p = static_cast<float*>(0X2edf);

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

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

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

#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; }  //類型轉換函數(shù)
    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);  

但是,下面這種繼承關系會轉換失?。?/p>

#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,并且有虛函數(shù)實現(xiàn),上行轉換不知道從哪條路徑進行轉換。下面的寫法則沒問題:

  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 看似支持下行轉換,這都是多態(tài)的緣故。上面的例子,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。但是,由于編譯器的常量傳播優(yōu)化,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;
}

到此這篇關于C++超詳細講解強制類型轉換的用法的文章就介紹到這了,更多相關C++強制類型轉換內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C語言 文件的打開與關閉詳解及示例代碼

    C語言 文件的打開與關閉詳解及示例代碼

    本文主要介紹C語言 文件的基礎知識,這里整理了相關資料及示例代碼,有興趣的小伙伴可以參考下
    2016-08-08
  • C++基礎知識實例解析(一)

    C++基礎知識實例解析(一)

    這篇文章主要對C++基礎知識實例解析,通過四個簡短的案例,鞏固大家的基礎知識,需要的朋友可以參考下
    2015-08-08
  • C語言如何正確的終止正在運行的子線程

    C語言如何正確的終止正在運行的子線程

    這篇文章主要介紹了C語言如何正確的終止正在運行的子線程,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-02-02
  • 數(shù)據結構之Treap詳解

    數(shù)據結構之Treap詳解

    這篇文章主要介紹了數(shù)據結構之Treap詳解,本文講解了Treap的基本知識、Treap的基本操作、Treap的高級操作技巧等,需要的朋友可以參考下
    2014-08-08
  • C語言實現(xiàn)二值圖像模擬灰值圖像顯示效果

    C語言實現(xiàn)二值圖像模擬灰值圖像顯示效果

    這篇文章主要為大家詳細介紹了C語言實現(xiàn)二值圖像模擬灰值圖像顯示效果,分為圖案法、抖動法兩個方法實現(xiàn),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++概念重載、覆蓋、隱藏的使用說明

    C++概念重載、覆蓋、隱藏的使用說明

    本篇文章介紹了,在C++中概念重載、覆蓋、隱藏的使用分析說明。需要的朋友參考下
    2013-05-05
  • C語言實現(xiàn)一個閃爍的圣誕樹

    C語言實現(xiàn)一個閃爍的圣誕樹

    本文詳細講解了C語言實現(xiàn)一個閃爍的圣誕樹,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-12-12
  • 求素數(shù),用vector存儲的實現(xiàn)方法

    求素數(shù),用vector存儲的實現(xiàn)方法

    本篇文章是對求素數(shù),用vector存儲的實現(xiàn)方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • opencv3/C++ 實現(xiàn)SURF特征檢測

    opencv3/C++ 實現(xiàn)SURF特征檢測

    今天小編就為大家分享一篇opencv3/C++ 實現(xiàn)SURF特征檢測,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • 關于C++中引用的定義與使用詳解

    關于C++中引用的定義與使用詳解

    這篇文章主要介紹了關于C++中引用和指針的區(qū)別,概念:引用是為已存在的變量取了一個別名,引用和引用的變量共用同一塊內存空間,需要的朋友可以參考下
    2023-07-07

最新評論