溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++的類型轉(zhuǎn)換

發(fā)布時間:2020-06-28 19:40:47 來源:網(wǎng)絡(luò) 閱讀:4685 作者:Dussssss 欄目:編程語言

C++類型轉(zhuǎn)換

類型轉(zhuǎn)換機制可以分為:隱式類型轉(zhuǎn)換 和 顯示類型轉(zhuǎn)換(強制類型轉(zhuǎn)換)

在C中我們這樣做類型轉(zhuǎn)換:

float a=1.023
int b;
b=a; //隱式類型轉(zhuǎn)換
或
b=int(a); //顯式類型轉(zhuǎn)換
或
b=(int)a;

C++中的類型轉(zhuǎn)換:
隱式類型轉(zhuǎn)換比較常見,在混合類型表達式中經(jīng)常發(fā)生.比如在表達式中存在short和int,那么就過會發(fā)生整型提升.四種強制類型轉(zhuǎn)換操作符:static_cast、dynamic_cast、const_cast、reinterpret_cast。

1、static_cast與dynamic_cast:
前者提供的是編譯時期的靜態(tài)類型檢測,后者提供的是運行時檢測.
static_cast: 1)完成基礎(chǔ)數(shù)據(jù)類型,2)同一個繼承體系中類型的轉(zhuǎn)換 3)任意類型與空指針類型void*之間的轉(zhuǎn)換。
dynamic_cast:使用多態(tài)的場景,增加了一層對真實調(diào)用對象類型的檢查

     char c  = 65;
     int *p = (int *)&c;
     cout<<(char)*p<<endl;//'A'
     *p = 5;
     int *q = static_cast<int *>(&c); //編譯報錯:error: invalid static_cast from type ‘char*’ to type ‘int*’

  在上面的例子中,Clike可以運行,然而修改過的*p如果使用,運行結(jié)果將會出現(xiàn)錯誤,而使用static_cast可以將錯誤在編譯時期檢查出
在不同繼承體系的自定義類型中:

class A
{
public:
  A(){}
  ~A(){}

private:
  int i, j;
};

class C
{
public:
  C(){}
  ~C(){}

  void printC()
  {
    std::cout <<"call printC() in class C" <<std::endl;
  }
private:
  char c1, c2;
};     

    A *ptrA = new A();
     C *ptrC = (C *)(ptrA);
     ptrC->printC(); //"call printC() in class C"
     //ptrC = static_cast<C*>(ptrA); //編譯報錯:error: invalid static_cast from type 'A*’ to type C*

  上面A C是兩個無關(guān)的類,然而使用Clike可以實現(xiàn)這種類型的強制轉(zhuǎn)換,這是十分危險的! 使用static_cast可以將這種潛在的危險在編譯器找出來.

  在同一繼承體系中:

  upcast(向上轉(zhuǎn)換即子類轉(zhuǎn)成父類):沒有問題.因為父類的行為都包含在子類中;

  downcast(向下轉(zhuǎn)換):有可能會出現(xiàn)問題,編譯時可能不會發(fā)現(xiàn).

  一個類的行為和自身的類型相關(guān).也就是一個A類型的指針總會優(yōu)先調(diào)用自己A類內(nèi)的函數(shù),當然發(fā)生繼承中的重寫(虛繼承等)例外.

#include <iostream>
#include <cstdio>

using namespace std;
class A
{
public:
  A():i(1), j(1){}
  ~A(){}

  void printA()
  {
    std::cout <<"call printA() in class A" <<std::endl;
  }

  void printSum()
  {
    std::cout <<"sum = " <<i+j <<std::endl;
  }

private:
  int i, j;
};

class B : public A
{
public:
  B():a(2), b(2) {}
  ~B(){}

  void printB()
  {
    std::cout <<"call printB() in class B" <<std::endl;
  }

  void printSum()
  {
    std::cout <<"sum = " <<a+b <<std::endl;
  }

  void Add()
  {
    a++;
    b++;
  }

private:
  double a, b;
};
int main()
{
     B *ptrB = new B;
     ptrB -> printSum();
     A *ptrA = static_cast<B *>(ptrB);
     ptrA -> printA();
     ptrA -> printSum();
     //打印結(jié)果:sum = 2
     //在進行upcast的時候,指針指向的對象的行為與指針的類型相關(guān)。

     ptrA = new A;
     ptrB = static_cast<B *>(ptrA);
     ptrB -> printB();
     ptrB -> printSum();
     //打印結(jié)果:sum = 0
     //在進行downcast的時候,其行為是“undefined”。

     B b;
     B &rB = b;
     rB.printSum();
     //打印結(jié)果: sum = 4
     A &rA = static_cast<A &>(b);
     rA.printA();
     rA.printSum();
     //打印結(jié)果: sum = 2
     //在進行upcast的時候,指針指向的對象的行為與引用類型相關(guān).

     A a;
     A &rA1 = a;
     rA.printSum();
     B &rB1 = static_cast<B &>(a);
     rB1.printB();
   //打印結(jié)果:sum = 4 
     rB1.printSum();
     //打印結(jié)果 :sum = 1.45863e-316
     //在進行downcast的時候,其行為是“undefined”。

     return 0;
}

  這里其實很明顯,在downcast轉(zhuǎn)換的時候,會出現(xiàn)一些跟指針或者引用類型相關(guān)的函數(shù)調(diào)用,但是因為指針或者引用(父類)

reinterpret_cast
僅僅是復制n1的比特位到d_r, 沒有進行必要的分析.interpret_cast是為了映射到一個完全不同類型\
的意思,這個關(guān)鍵詞在我們需要把類型映射回原有類型時用到它。我們映射到的類型僅僅是為了故弄\
玄虛和其他目的,這是所有映射中最危險的。(這句話是C++編程思想中的原話

const_cast
去除const常量屬性,使其可以修改volatile屬性的轉(zhuǎn)換 易變類型<->不同類型.

#include <iostream>
#include <cstdio>
#include <string>

using namespace std;

class A {
    public:
    A(){};
    int m_a;
};

class B {
    public:
    int m_b;
};

class C : public A, public B {};

int main()
{
    const A a;
    //a.num = 1;
    const_cast<A&>(a).m_a = 2;
    //a.num = 3;編譯不能通過,說明const_cast只能轉(zhuǎn)換一次,不是永久脫離原有const屬性
    cout<<a.m_a<<endl;
    int n = 9;
    double d_s = static_cast<double>(n);
    double d_r = reinterpret_cast<double&>(n);
    cout<<d_r<<endl;//4.24399e-314
    //在進行計算以后, d_r包含無用值. 這是因為 reinterpret_cast僅僅是復制n1的比特位到d_r, 沒有進行必要的分析.interpret_cast是為了映射到一個完全不同類型的意思,這個關(guān)鍵詞在我們需要把類型映射回原有類型時用到它。我們映射到的類型僅僅是為了故弄玄虛和其他目的,這是所有映射中最危險的。(這句話是C++編程思想中的原話
    return 0;
}

#include <iostream>
#include <typeinfo>
#include <cstdio>

using namespace std;

class A{
public:
virtual void foo(){
cout<<"A foo"<<endl;
}
//虛函數(shù)的出現(xiàn)會帶來動態(tài)機制 Class A 至少要有一個虛函數(shù)
void pp(){
cout<<"A pp"<<endl;
}
};

class B: public A{
public:
void foo(){
cout<<"B foo"<<endl;
}
void pp(){
cout<<"B PP"<<endl;
}
void functionB(){
cout<<"Excute FunctionB!"<<endl;
}
};

int main()
{
B b;
A pa = &b;
pa->foo();
pa->pp();
//基類指針可以指向派生類,但是只能調(diào)用基類和派生類都存在的成員,也就是說不能調(diào)用派生類中新增的成員!
//pa->FunctionB();//error: 'class A' has no member named 'FunctionB'
if(dynamic_cast<B
>(pa) == NULL){
cout<<"NULL"<<endl;
}else{
cout<<typeid((dynamic_cast<B>(pa))).name()<<endl;
dynamic_cast<B
>(pa)->foo();
dynamic_cast<B>(pa)->pp();
dynamic_cast<B
>(pa)->functionB();
}
A aa;
//B pb = &aa;派生類不能指向基類
B
pbNull = NULL;
pbNull->functionB();//fine
pbNull->pp();//fine
//pbNull->functionB(); crash!foo調(diào)用了虛函數(shù),編譯器需要根據(jù)對象的虛函數(shù)指針查找虛函數(shù)表,但為空,crash!
return 0;
}

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI