1. 程式人生 > >C++ primer 5th : 第四章筆記

C++ primer 5th : 第四章筆記

第四章: 表示式

  基本概念:

    運算子:  一元 , 二元 , 三元

    組合運算子 和 運算物件 : 

        優先順序:  使用  () 避免優先順序的混淆的問題

        結合律:  

        求值順序: 二元運算子兩邊的表示式計算順序可能存在差異 , 應該避免

    對優先順序 , 結合率 , 求值順序的解釋:

        

 //如下表達式:
 //我們假設 g() 的操作是將全域性變數 i = 10 的值 乘以 2 返回
 //我們假設 h() 的操作是將全劇變數 i 的值 + 2 返回
f() + g() * h() + j() // 優先順序 : 存在於組合運算當中 , 也就是多個運算子參與 , 優先順序是運算子 與 運算子之間的關係 // 結合率 : 我們針對 上述表示式 可以 使用 結合率 的方式改變運算子的優先順序 // ( f() + g() ) * h() + j() // 求值順序 : 對於 單個二元運算子來說 , 先算右邊 還是 先算左邊 好像只有在 邏輯運算子 : || && 上才有體現 , 但是在 * 上可能存在差異 , 如上 , // 如果我們先算左邊 , 在算右邊 ; 那 g() * h() 的結果就是 20 * 22 = 440 // 如果我們先算右邊 , 在算左邊 ; 那 g() * h() 的結果就是 24 *12 = 288
// 所以我覺得 能不在一個運算子兩邊修改 共有的部分 是最好的。

 

    運算物件轉換 :

        表示式中勻允許不同型別之間的轉換 , 編譯器會自動的轉換

        int 還會有型別提升

        在算術型別之間的運算 需要保證 運算結果不溢位 , 且精度損失降低到最小 , 才有運算結果的型別一定是其中的最高型別。

    過載運算子:

        將運算子 賦予 在某一個非基本型別上面新的含義

    左值 與 右值 :

        將一個物件當作左值來使用 : 代表的是當前物件本身

        將一個物件當作右值來使用 : 代表的是當前物件的拷貝

        需要右值的地方可以使用 左值代替 , 但是反過來通常不行

       decltype 與 左值 右值:

        如果 decltype 的是一個左值型別 , 那麼得到一定是一個引用型別 , 如果decltype 的是一個右值型別 , 那麼得到的一定是一個 普通型別

#include <iostream>
  
using namespace std;

int main()
{
    int a = 10;         //普通的類新  int
    int & b = a;        //引用型別    int &
    decltype(b) c = a;  //c 的型別為  int &
    c = 20;             //修改C 就是 修改a
    cout << a << endl;  //結果為20
    return 0;
}
~       
decltype 的是的左值型別

 


 

算數運算子:

  略


 

邏輯運算子:

  注意 : &&  || 有運算子求值順序的規定 , 先算左邊在算右邊 ,  左邊滿足的順序右邊不再計算 , 這就是短路

 


 

賦值運算子:

    •  = 左邊必須是一個可以修改的左值
    • C++11 允許使用 {} 擴起來的初始值列表做右值
    • 連續賦值運算 滿足 右邊結合率 : a = b = 10
    • 賦值運算子優先順序低 : if (  1 != (i = get_value()) 

 


 

遞增運算子 和 遞減運算子:

    •  ++ , --  運算子 需要左值物件 :   (i++)++ 錯誤 , i++返回的是右值

成員運算子:

  . 與 ->


 

條件運算子:

  >  , <  , >=  ......


 

位運算:

  & , | , ~ , ^


 sizeof 運算子:

  sizeof(型別) 可以獲得該型別佔用的記憶體大小 , C++ 可以讓sizeof 直接訪問 類的成員的  , 以此的其成員型別佔用的記憶體的大小.  sizeof (class::number)

  •  sizeof(陣列) : 陣列不會退化成指標)
  •    sizeof(類型別) : 固有成員的記憶體和 : 不包括成員指向的 堆空間的記憶體
  •    sizeof  返回的型別是一個 constexpr

 


 

逗號運算子:

  結合律從左邊向右邊 , 最後的結果為最右邊的表示式子 , 且如果最右邊的表示式是左值 , 整個表示式結果為左值  , 否則為右值


 

型別轉換:

  如果兩個型別之間可以相互轉換 , 那麼他們就是有關聯的.

  無須程式設計師的介入的型別轉換稱為隱式型別轉換.

  

  顯式型別轉換:

    static_cast<>():

        不能擦除引用 , 指標 的 底層 const 屬性。

        大範圍型別 向 小範圍型別 ,  高精度 向 低精度  : 告訴編譯器我是故意轉換的 , 而且我能確保這樣作的後果沒有問題 , 你把警告給我關了吧

    const_cast<>():

        只能改變物件的頂層const屬性 , 不能值型別轉換:

        只有當底層const指向的物件不是 const ,  才能進行擦除const :

#include <iostream>

using namespace std;

int main()
{
    int a = 10;                      //a 為非const
    const int & b = a;               //底層const , 但是 a 為非const
    int & c = const_cast<int &>(b);  //我們可以擦除掉const 屬性
    c = 30;
    cout << a << endl;               //30 : 成功修改


    const int aa = 10;                //aa為const
    const int & bb = aa;              //指出底層const ,底層確實也是const
    int & cc = const_cast<int &>(bb); //擦除掉底層的const , 但是為cc重新開闢了空間,也就是 cc 和 aa 指向不是同一個記憶體區域了
    cout << aa << endl;               //10
    cout << cc << endl;
    return 0;
}

 

    dynamic_cast<>()

      用於具有繼承體系之間的轉換  指標和引用 , 類必須具有虛擬函式  ,  父類指標指向的 子類物件向 向子類指標轉換 ,  或者父類引用指向子類的向子類引用轉換使用:

      父類指標 指向父型別物件 向 子型別指標轉換 |   一個父類的兩個子類之間轉換   最後為 NULL

      父類引用 指向父型別物件 向 子型別引用轉換 丟擲 std::bad_cast 異常

       

#include <iostream>

class A{
public:
  virtual ~A(){}  
}
class B :public A{
};
class C :public A{
};


int main()
{
    C * c = new C();
    B * b = new B();
    A * a = new A();

    B *bc = dynamic_cast<B*>(c);    //2個子類之間不能 dynamic_cast
    if(NULL == bc)
    {
        cout <<"2 個子類指標之間不能發生轉換!" << endl;
    }

    B *ba = dynamic_cast<B*>(a);    //父類轉換成子類 , 不安全
    if(NULL == ba)
    {
        cout <<"父類指標 指向 父類物件 不能向子類指標轉換!"<<endl;
    }
    A ra;
    A & aa = ra;
    try{
        B & b = dynamic_cast<B &>(aa);
    }catch(std::bad_cast){
        cout <<"父類引用  指向 父類物件  不能向子類引用轉換!" <<endl;
    }
    return 0;

}

輸出結果 : 
2 個子類指標之間不能發生轉換!
父類指標 指向 父類物件 不能向子類指標轉換!
父類引用  指向 父類物件  不能向子類引用轉換!

 

    reinterpret_cast<>():

      不建議使用