欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++超詳細(xì)講解強(qiáng)制類型轉(zhuǎn)換的用法

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

static_cast

static_cast<type-id>(expression)

expression 轉(zhuǎn)換為 type-id 類型。static_cast 是靜態(tài)類型轉(zhuǎn)換,發(fā)生在編譯期。這種轉(zhuǎn)換不會(huì)進(jìn)行運(yùn)行時(shí)的動(dòng)態(tài)檢查(RTTI),因而這種轉(zhuǎn)換可能是不安全的。static_cast 典型應(yīng)用場景如下:

1. 類的層級(jí)結(jié)構(gòu)中,基類和子類之間指針或者引用的轉(zhuǎn)換。

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

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

下面舉例說明:

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

對于上行轉(zhuǎn)換,肯定是安全的。

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

對于下行轉(zhuǎn)換:

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

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

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

此外,對于兩個(gè)不存在繼承關(guān)系的兩個(gè)類之間轉(zhuǎn)換,總是失敗的,編譯器報(bào)錯(cuò):

#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ù)據(jù)類型間的轉(zhuǎn)換。這種轉(zhuǎn)換也是不安全的,需要程序員自行保證安全轉(zhuǎn)換。 例如 int 轉(zhuǎn) short,直接高位截?cái)?;?short 轉(zhuǎn) int 則高位根據(jù)符號(hào)位填充。兩種不同類型指針間相互轉(zhuǎn)換是相當(dāng)危險(xiǎn)的,例如 int* 轉(zhuǎn) float*。將 int 轉(zhuǎn)換為指針類型也是危險(xiǎn)的轉(zhuǎn)換,例如 float* p = static_cast<float*>(0X2edf);

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

4. 把其他類型轉(zhuǎn)換為 void 類型。

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

#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; }  //類型轉(zhuǎn)換函數(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 轉(zhuǎn)換為 type-id 類型,type-id 必須是類的指針、類的引用或者是 void *;如果 type-id 是指針類型,那么 expression 也必須是一個(gè)指針;如果 type-id 是一個(gè)引用,那么 expression 也必須是一個(gè)引用。

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

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

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

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

但是,下面這種繼承關(guān)系會(huì)轉(zhuǎn)換失?。?/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;
}

上面這個(gè)例子,雖然也是上行轉(zhuǎn)換,但是存在兩條路徑,在 B 和 C 都繼承于 A,并且有虛函數(shù)實(shí)現(xiàn),上行轉(zhuǎn)換不知道從哪條路徑進(jìn)行轉(zhuǎn)換。下面的寫法則沒問題:

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

下行轉(zhuǎn)換:看個(gè)例子。

#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;
}

其實(shí) dynamic_cast 本質(zhì)只支持上行轉(zhuǎn)換,只會(huì)沿著繼承鏈向上遍歷,找到目標(biāo)類型則轉(zhuǎn)換成功,否則失敗。dynamic_cast 看似支持下行轉(zhuǎn)換,這都是多態(tài)的緣故。上面的例子,pa1 雖然類型是 A,但實(shí)際指向 B,沿著 B 向上可以找到 B,因?yàn)榈谝粋€(gè)轉(zhuǎn)換可以成功。而 pa2 指向 A,沿著 A 向上找不到 B 類型,因而轉(zhuǎn)換失敗。

因而在有繼承關(guān)系的類的轉(zhuǎn)換時(shí)候, static_cast 轉(zhuǎn)換總是成功的, dynamic_cast 顯然比 static_cast 更加安全。

const_cast

const_cast 用來去掉表達(dá)式的 const 修飾或 volatile 修飾,也就是將 constvolatile 類型轉(zhuǎn)換為非 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 的打印值應(yīng)該是 222。但是,由于編譯器的常量傳播優(yōu)化,std::cout<< "n = " << n << std::endl; 會(huì)被編譯器替換成類似 std::cout<< "n = " << 111 << std::endl; 的語義。

reinterpret_cast

reinterpret_cast 轉(zhuǎn)換直接對二進(jìn)制位按照目標(biāo)類型重新解釋,非常粗暴,所以風(fēng)險(xiǎn)很高,慎重使用。

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

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

相關(guān)文章

最新評(píng)論