C++Primer學習——類型轉換

無符號之間的運算

當一個是無符號類型,另一個是帶符號類型:
若是無符號不小於帶符號,那麼帶符號轉換成無符號。
若是無符號小於帶符號,當無符號類型的全部值都能存到帶符號中時,則無符號轉換成帶符號,不然,
帶符號類型轉換成無符號類型。
好比:
有兩個類型分別是 long 和 unsigned int,若是大小相同,long類型轉換成unsigned int,不然unsigned轉換成long類型ios

隱式類型:

數組轉換成指針:
decltype,取地址&,sizeof以及typeid(未知)不會轉換
若是用一個引用初始化數組也不會發生轉換。(引用初始化數組?)c++

類類型定義的轉換:程序員

string s;
while(cin >> s)        //IO庫定義了從istream向bool的轉換規則,取決因而否讀入成功
{
}

顯式轉換:

cast-name (exp); 將exp轉換成type類型 express

一、static_cast:(只要不包含底層const)

主要在如下幾種場合中使用:
1.用於類層次結構中,基類和子類之間指針和引用的轉換;
當進行上行轉換,也就是把子類的指針或引用轉換成父類表示,這種轉換是安全的;
當進行下行轉換,也就是把父類的指針或引用轉換成子類表示,這種轉換是不安全的,也須要程序員來保證;
2.用於基本數據類型之間的轉換,如把int轉換成char,把int轉換成enum等等,這種轉換的安全性須要程序員來保證;
3.把void指針轉換成目標類型的指針,是及其不安全的;
注:static_cast不能轉換掉expression的const、volatile和__unaligned屬性。
參考連接數組

int a = 100;
double t = static_cast<double>(a) / 6;
cout << t << endl;  
//16.6667

向上轉換(好像並非確定安全的記住原始的指針類型 ?):安全

class Base1{
    //int a;
};
class Base2{
    public:
    int b;
};
class Derived: public Base1, public Base2{
};
int main()
{
    int a;
    void *p;
    Derived pd;
    pd.b = 10;
    cout << pd.b <<endl;
    cout << "pb: " << &pd<< endl;
    Base2* pb1 = static_cast<Base2 *>(&pd);
    cout << pb1->b <<endl;
    cout << "Derived to Base2: " << pb1 << endl;
    return 0;
}
10
pb: 0x68fefc
10
Derived to Base2: 0x68fefc

二、const_cast:(只能改變底層const)

使用const_cast去除const限定的目的不是爲了修改它的內容,一般是爲了函數可以接受這個實際參數ide

const char *cp;
char *p = const_cast<char*>(cp);//經過p寫值是未定義行爲
char *p = static_cast<char*>(cp);//error
static_cast<string>(cp);         //yes,字符串字面值轉變成string(未實踐)
const int a = 100;
int *pA = const_cast<int *>(&a);
*pA = 200;
int &refA = const_cast<int &>(a);
refA = 300;
//  int *pA1 = static_cast<int *>(&a);  Error   
cout << "*pA:" << *pA << endl;//300  
cout << "refA:" << refA << endl;//300  
cout << "a:" << a << endl;//100  
system("pause");

下面是網上摘錄的一段解釋:(or常量摺疊解釋)
const只是告訴編譯器不能修改而不是真正地不可修改,若是程序員不注意而去修改了它會報錯,如今咱們利用const_cast去除了常量性,而後經過指針和引用對其進行了修改,因此經過指針打印或者引用傳參的時候就能看出其內存確實變化了,但爲了保護val這個變量原本的const特性,因此每次咱們使用val時,系統都將其替換成初始值100,確保了val仍是「不可變」的
參考博客函數

#include <iostream>
using namespace std;
void f(int* p) {
  cout << *p << endl;
}
int main(void) {
  const int a = 10;
  const int* b = &a;
  // Function f() expects int*, not const int*
  //   f(b);
  int* c = const_cast<int*>(b);
  f(c);
  // Lvalue is const
  //  *b = 20;
  // Undefined behavior
  //  *c = 30;
  int a1 = 40;
  const int* b1 = &a1;
  int* c1 = const_cast<int*>(b1);
  // Integer a1, the object referred to by c1, has
  // not been declared const
  *c1 = 50;
  return 0;
}
http://www.ibm.com/support/knowledgecenter/SS3KZ4_9.0.0/com.ibm.xlcpp9.bg.doc/language_ref/keyword_const_cast.htm

在函數重載上面的應用:spa

const string &shorterString(const string& a, const string& b)
{
return a.size() <= b.size() ? a : b;
}
string &shorterString(string& a, string& b)
{
auto &r = shorterString(const_cast<const string&>(a),
const_cast<const string&>(b));
return const_cast<string &>(r);
}

三、reinterpret_cast:(本質上依賴於機器)

能夠進行任意之間的轉換,不會報錯,可是可能破壞程序.net

int *ip;
char *pc = reinterpret<char*>(ip);
string str(pc);                            //pc所指真實對象是一個int,因此有問題
與舊式轉換相似的功能
int *op;   
char *p = (char*)op;
MSDN上的一個應用- -  ,不是很懂reinteroret_cast有什麼用
#include <iostream>  
using namespace std;  
  
// Returns a hash code based on an address  
unsigned short Hash( void *p ) {  
   unsigned int val = reinterpret_cast<unsigned int>( p );  
   return ( unsigned short )( val ^ (val >> 16));  
}  
  
using namespace std;  
int main() {  
   int a[20];  
   for ( int i = 0; i < 20; i++ )  
      cout << Hash( a + i ) << endl;  
}

4.dynamic_cast轉換 :

(想使用基類指針或者引用執行某個派生類非虛函數操做)
dynamic_cast是動態轉換,只有在基類指針轉換爲子類指針時纔有意義。(子類指針轉換爲基類指針原本就是能夠的:基類指針指向子類對象OK)。
可是基類指針轉換爲子類指針,並非每一次都有效:只有基類指針自己指向的是一個派生類的對象,
安全性:
這須要從它的返回值進行討論,若是符合繼承體系且原始指針是指向派生類的對象的,那麼返回值將是一個正確的指針值,不然會返回NULL。因此,咱們能夠對返回值進行判斷來進行判定到底轉換是否正確,從而保證程序的健壯性
必須是一個帶有虛函數的類。由於dynamic_cast是在對象的內存模型中保存了offset值來實現轉換的,這些offset值是保存在虛表(vtbl)中的
虛表參考<Inside c++ object model>:

class MyCompany
{
public:
    void payroll(Employee *pe);
    //
};
void MyCompany::payroll(Employee *pe)
{
    Programmer *pm = dynamic_cast<Programmer *>(pe);
    
    //若是pe實際指向一個Programmer對象,dynamic_cast成功,而且開始指向Programmer對象起始處
    if(pm)
    {
        //call Programmer::bonus()
    }
    //若是pe不是實際指向Programmer對象,dynamic_cast失敗,而且pm = 0
    else
    {
        //use Employee member functions
    }
}

class A
{
public:
   virtual ~A(){}         //虛函數 多態
};
class B:public A
{
public:
    int m;
};
A* pObjA = new A();
B* pObjB  = NULL;
pObjB = dynamic_cast<B*>(pObjA);  //編譯經過 
//實際運行結果:pObjB == NULL   // dynamic_cast保證轉換無效 返回NULL

來自爲知筆記(Wiz)

相關文章
相關標籤/搜索