c++ primer 筆記,第六章

  1. 局部靜態對象使用static聲明,聲明一次後下次再調用該函數,則該聲明語句則被忽略

    // 練習6.7,第一次被調用時返回0,以後每次調用返回值加一 
    size_t count()
    {
        static size_t ctr = 0;
        if (ctr) return ctr++;
        else 
        {
            ++ctr;
            return 0;
        }
    }
  2. 當函數無需修改引用形參的值時最好使用常量引用

  3. 使用實參初始化形參時會忽略頂層const
  4. 使用普通引用會極大地限制函數所能接受的實參類型,我們不能把const 對象、字面值或者需要類型轉換的對象傳遞給普通的引用形參

    // 由於該形參爲非常量引用,若定義一個const string或者字面值常量,則無法調用該函數 
    bool is_empty(string &s)  { return s.empty(); } 
  5. 如果所有實參類型相同,可以傳遞一個名爲initializer_list的標準庫類型用來實現可以處理不同數量實參的函數,類型定義在同名頭文件中
    (1)與vector一樣,該類型也是一種模板類型,但其對象中的元素永遠是常量值,我們無法改變initializer_list對象中元素的值;
    (2)拷貝或賦值一個initializer_list對象不會拷貝列表中的元素;拷貝後,原始列表與副本共享元素(因爲該對象中的元素不可能被改變,所以在賦值或拷貝的行爲中完全可以與原始列表共享而不用擔心其他任何問題,並且還避免了拷貝的開銷);
    (3)lst.size(), lst.begin(), lst.end();
    (4)如果想向initializer_list形參中傳遞一個值的序列,則必須把序列放在一對花括號中;

    // 練習6.27 
    template<typename T>
    int sum(initializer_list<T> lst)
    {
        int sum = 0;
        for(const auto &beg : lst)   // const auto& 型,避免多餘的拷貝行爲發生 
            sum += beg;
        return sum;
    } 
    
    int main()
    {
    /*  
        for (int i = 0; i < 10; ++i)
            cout << count() << endl;
    */
        cout << sum({2,3,4,5}) << endl;  //實參必須放在一對花括號中 
        cout << sum({1,2,3}) << endl;
        return 0;
    }
  6. return語句有兩種形式,一種是空return,即 return,另一種是返回一個表達式,即return expression ;一個返回類型是void的函數也能使用return 語句的第二種形式,不過此時 return 語句的 expression 必須是另一個返回void的函數
  7. 調用運算符的優先級與點運算符和箭頭運算符相同,並且也符合左結合率,如果函數返回指針、引用或類的對象,我們就可以使用函數調用的結果訪問結果對象的成員
  8. C++11新標準規定,函數可以返回花括號包圍的值的列表,如果函數返回的是內置類型,則花括號包圍的列表最多包含一個值,如果函數返回的是類類型,由類本身定義初始值如何使用

    
    #include <iostream>
    
    
    #include <vector>
    
    using namespace std; 
    //例:該函數返回值爲vector<string>類型 
    vector<string> process()
    {
        return {"abc", "cd"};
    } 
    
    int main()
    {
        vector<string> a;
        a = process();
        cout << a[0] << endl;
        return 0;
    }
  9. 關於返回數組指針:

    typedef int arrT[10];   //arrT是一個類型別名,它表示的類型是含有10個整數的數組
    
    using arrT = int[10];   // 等價於上面的聲明
    
    arrT* func(int i);      // func返回一個指向含有10個整數的數組的指針

    int (*fun(int i)) [10];
    (1)func(int i)表示調用func函數時需要一個int型的實參;
    (2)(*func(int i))意味着我們可以對函數調用的結果執行解引用操作;
    (3)(*func(int i)) [10]表示解引用func的調用將得到喲個大小是10的數組;
    (4)int (*fun(int i)) [10]表示數組中的元素是int型

  10. 尾置類型返回,在本該出現返回類型的地方放置一個auto, 例如:auto func(int i) -> int(*0[10];

  11. 關於函數重載:
    (1)重載函數中不允許兩個函數除了返回類型不同其他類型都相同,即意味着返回類型不能用來區別函數

    int  func(int i);
    bool func(int i);    // 錯誤:遇上一個函數相比只有返回類型不同 

    (2)擁有頂層const的形參無法和無頂層const的形參區別開來;

    int  func(int );
    int  func(int* const);    // 錯誤:重複聲明瞭func 

    (3)如果形參是某種類型的指針或引用,則可以通過區分其指向的是常量對象還是非常量對象可以實現函數重載,此時的cons是底層的

    int  func(int& );
    int  func(const int&);    // 作用於常量引用 
  12. const_cast再函數重載中的作用,如果一個函數的形參爲const版本,返回值爲const&的類型,此時若想用非常量實參使用該函數,並得到一個普通的引用,可以使用const_cast先將非常量實參轉換爲常量引用,調用const版本函數,然後對返回結果再用const_cast轉換爲普通引用,保障整個過程的安全

  13. 一旦一個形參被賦予了默認值,則它後面的所有實參都必須有默認值,在給定的作用於中一個形參只能被賦予一次默認值,後續的函數聲明只能爲沒有默認值的形參添加默認實參

    string func(a,b,char = ' ');
    
    string func(a,b,char = '*');   //錯誤,重複聲明
    
    string func(a = 5, b = 8, char);  // 正確,在此之前char已經有默認值 
  14. constexpr函數的返回值及所有形參類型都得是字面值類型(在編譯時就得到計算,算數類型、引用和指針都屬於字面值類型,自定義類,IO庫、string類型都不屬於字面值類型),而且函數體中有且只有一條return語句 ;爲了嗯那個在編譯期間隨時展開,constexpr函數被隱式地指定爲內聯函數,我們允許constexpr函數返回值並非一個常量(返回結果可以是一個常量表達式);
  15. assert的行爲依賴於一個名爲NDEBUG的預處理變量的狀態,如果定義了NDEBUG,則assert什麼也不做,默認狀態下沒有定義NDEBUG ;
  16. 預處理器定義的5個名字 (頭文件爲cstdio)
    (1)_ _fun_ _:當前調試的函數的名字;
    (2)_ _FILE_ _ :存放文件名的字符串字面值;
    (3)_ _LINE_ _:當前行號;
    (4)_ _TIME_ _:文件編譯時間;
    (5)_ _DATE_ _:文件編譯日期;
  17. 可以直接使用和i資訊那個函數的指針調用該函數,無需提前解引用指針

    // func函數返回一個函數指針,該函數指針所指的函數的形參爲一個int* 和一個 int,返回值爲int 
    int (*func(int)) (int*, int);
    // 等價於 
    using PF = int(*)(int*, int);
    PF func(int);
    // 等價於
    auto func(int) -> int (*)(int*, int);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章