<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                ## 一.參數 1. **形參** 函數定義時,參數的名稱。 2. **實參** 形參的初始值。第一個實參初始化第一個形參,第二個實參初始化第二個形參,以此類推。盡管實參與形參存在對應關系,但是并沒有規定實參的求值順序。編譯器能以任意可行的順序對實參求值。 ## 二.參數傳遞 1. 傳值調用 + C++中參數傳遞的缺省初始化方法是把實參的值拷貝到參數的存儲區中,此時函數不會訪問當前調用的實參。 + 數組作參數時,傳遞的是數組第一個元素的地址。 > 數組形參會被編譯器替換成指向數組第一個元素的指針形參。 + 此時在函數內改變形參的值對實參沒有影響。 2. 傳指針調用 + 指針使我們可以間接地訪問它所指的對象,通過指針可以修改它所指對象的值。 + 修改指針的指向對實參無影響。 3. 傳引用調用 + 當參數是引用時,函數接收的是實參的左值。此時修改參數可以影響實參。 + 傳引用調用通常用于以下情況: + 需要直接修改實參 + 傳遞一個較大的對象 + 從函數返回多個值 4. 引用和指針參數的關系 >引用必須被初始化為指向一個對象,一旦初始化了,它就不能再指向其他對象。指針可以指向一系列不同的對象也可以什么都不指向。 >[info]如果一個參數可能在函數中指向不同的對象,或者這個參數可能不指向任何對象,則必 須使用指針參數。 ## 三.默認參數 1. 函數調用的實參按位置解析,缺省實參只能用來替換函數調用缺少的尾部實參。 2. 定義/聲明時,默認參數應 **從右向左** 依次定義。 >[danger] [錯了] `int fun(int a = 0,double b,char c)` >[success] [對的] `int fun(int a,double b,char c = '\n')` 3. 調用函數時, 參數 **從左向右** 匹配。 ```c++ #include <iostream> using namespace std; int fun(int a = 0,int b = 1,int c = 2,int d = 3) { cout<<"a="<<a<<";b="<<b<<";c="<<c<<";d="<<d<<";"<<endl; return 0; } int main() { fun(2019);//a=2019 fun(22,33);//a=22 b=33 fun(2019,2020,2021);//a=2019 b=2020 c=2021 fun(2017,2018,2019,2020);//a=2017 b=2018 c=2019 d=2020 } ``` >[test] >a=2019;b=1;c=2;d=3; >a=22;b=33;c=2;d=3; >a=2019;b=2020;c=2021;d=3; >a=2017;b=2018;c=2019;d=2020; >Press any key to continue 3. 既有聲明又有定義時,定義中可省略默認參數;只有定義時,默認參數須出現在定義中。 4. 含有普通局部變量的表達式不能作為默認實參。除此之外,只要表達式的類型能轉換成形參所需的類型,該表達式就能作為默認實參。 >[success]默認參數的函數調用在編譯期時就需要確定其值,或者其地址。 > >+ 常量表達式能夠確定其值。 >+ 靜態變量能確定其地址。 >+ 含有靜態變量的表達式能夠確定其值。 >+ 普通局部變量本身在編譯期值不確定,地址也不確定。 >+ 含有普通局部變量的表達式的值在編譯期無法確定。 >[warning]默認實參表達式的值的計算發生在函數調用的時候。 >[success] [14+] 允許不被求值的局部變量作為函數形參,如 `sizeof(局部變量)` ## [$]四.省略符形參 ### 1.省略符形參實現可變參數 1. 定義一個可變參數的函數:在形參列表末尾加上 `...` ```c++ void one_more_args(int size,...) { //your code } void zero_more_args(...) { //your code } ``` 接下來便可以這么調用: ```c++ one_more_args(5,1,2,3,4,5); zero_more_args(1,2,3); zero_more_args(1,2,3,4); ``` 需要注意的是,如果省略符形參前面沒有固定的參數,那么這些省略號參數是不能正常接收的。 2. 接收可變參數 需要引入 `cstdarg` 或 `stdarg.h` 頭文件。并確保函數至少有一個固定的形參。 ```c++ long add(int num,...) { long result = 0; va_list args;//定義一個形參列表 va_start(args, num); //初始化 args 變量,其中 size 是最后一個已知形參 for (int i = 0; i < num; i++) { result += va_arg(args, int);//讀取傳入的參數 } va_end(args); //參數讀取完畢 return result; } ``` 接下來就可以實現無限的數字相加了: ```c++ cout<<add(4,1,5,8,7); ``` >[test] >21 ### 2.省略符形參實現可變參數的淺層原理 函數調用時,參數(除了引用形參)會按照形參表的順序依次入棧,每個實參彼此相鄰(由于編譯器的內存對齊策略,這些實參之間可能會有少量空隙)。這樣,我們就可以通過指針來依次訪問實參。 + `va_list` 存儲有函數參數列表的信息,理論上是一個字符指針。 + `va_start` 是一個宏函數。第一個參數為 `va_list` ,第二個參數為最后一個固定參數。根據固定參數的存儲位置和大小,可以算出第一個不定參數的位置,并賦值給第一個參數。 + `va_arg` 是一個宏函數。第一個參數為 `va_list` ,第二個參數為讀取的類型名稱。根據第一個參數和類型名稱的大小,可以算出下一個參數的內存位置。 + `va_end` 是一個宏函數。將第一個參數置為空。 ### 3.省略符形參的應用 + `scanf` + `printf` ### 4.省略符形參的局限性 1. 對類類型的支持不友好,有時構造函數無法正常調用。 ```c++ class MyInt { private: int num_; public: MyInt(int num) : num_(num) { cout << "構造MyInt,值為 " << num << endl; } friend MyInt &operator+=(MyInt &m1, const MyInt &m2); friend ostream &operator<<(ostream &os, const MyInt &m); }; MyInt &operator+=(MyInt &m1, const MyInt &m2) { m1.num_ = m1.num_ + m2.num_; return m1; } ostream &operator<<(ostream &os, const MyInt &m) { return os << m.num_; } MyInt add(int num, ...) { MyInt result = 0; va_list args; //定義一個形參列表 va_start(args, num); //初始化 args 變量,其中 size 是最后一個已知形參 for (int i = 0; i < num; i++) { result += va_arg(args, MyInt); //讀取傳入的參數 } va_end(args); //參數讀取完畢 return result; } ``` 相加: ```c++ cout << add(4, 1, 5, 8, 7); ``` >[test] >構造MyInt,值為 0 >21 從輸出結果來看,這里的四個省略符參數并沒有正常構造。 >[warning] 一般省略符形參應該僅僅用于C和C++通用的類型。 2. 不支持引用形參。因為引用形參不會占用空間。 3. 編譯器不會對省略符形參進行類型檢查。 ## \[11+\][$]五.initializer list 形參 `initializer_list` 是一種標準庫模板類,用于表示某種特定類型的值的數組。 它定義在 `initializer_list` 頭文件中。 ### 1.用途 + 實參數量未知 + 全部實參的類型相同 ### 2.基本操作 + `initializer_list<T> list;` 定義一個`initializer_list`。 + `initializer_list<T> list{a,b,c,...};` 定義并使用大括號初始化一個`initializer_list`。 + 和其他對象一樣的拷貝操作 + `list.size()` 元素的數目。 + `list.begin()` 返回一個迭代器,指向首元素。 + `list.end()` 返回一個迭代器,指向末尾元素的下一個元素。 ### 3.initializer_list 形參實現不定參數 ```c++ long add(initializer_list<int> list) { long result = 0; //通過迭代器訪問元素 for (auto iter = list.begin(); iter != list.end(); iter++) result += *iter; return result; } ``` 調用函數: ```c++ //調用時,這些參數需要加上大括號 cout << add({1, 3, 5, 7, 9}); ``` >[test] >25 ## \[11+\][$]六.轉發 ### 1.概念 + 把實參傳遞給其他函數 ### 2.不完整的轉發 #### 例1 ```c++ //用于調用其他函數,其中 f 是一個可調用對象,包括函數指針、函數對象 //這種轉發會丟掉 頂層的const 和引用 template <typename F, typename T1, typename T2> void call(F f,T1 t1,T2 t2) { //調用前的處理 f(t1,t2); //調用后的處理 } void f(int v1, int &v2) //注意v2是一個引用 { v2 += v1; } ``` 再定義下面兩個變量: ```c++ int i = 66; int j = 600; ``` 當我們直接調用 `f`時: ```c++ f(i,j); cout<<i<<","<<j<<endl; ``` >[test] >66,666 當我們通過 `call` 間接調用 `f`時: ```c++ call(f,i,j); cout<<i<<","<<j<<endl; ``` >[test] >66,600 很顯然,`call` 和直接調用 `f` 的結果是不一樣的。原因在于這兩種方式調用 `f` 時,`v1` 引用的是 `i`;而后者在調用 `call` 時, `i` 會被復制一份到 `t1`, `v1` 引用的是 `t1` 。 #### 例2 為了解決上面的問題,我們調整 `call` 函數: ```c++ //用于調用其他函數,其中 f 是一個可調用對象,包括函數指針、函數對象 //傳入左值時,t1,t2為左值引用;傳入右值時,t1,t2為右值引用。具體請參見 引用 template <typename F, typename T1, typename T2> void call(F f,T1 &&t1,T2 &&t2) { //調用前的處理 f(t1,t2); //調用后的處理 } void f(int v1, int &v2) //注意v2是一個左值引用 { v2 += v1; } void f2(int &&v1, int &v2) //注意v2是一個左值引用,v1是一個右值引用 { v2 += v1; } ``` 這樣,通過 `call` 調用 `f` 和直接調用 `f` 就沒有什么差別了。 但是,`call` 不能調用 `f2` 。因為具名的右值引用是一個左值,而左值是不能作為右值引用的參數的。 ### 3.std::forward 實現完美轉發 + **頭文件** `utility` + **功能** 保持給定實參的引用屬性以及頂層的 `const` 屬性。 + **格式** `std::forward<參數的類型>(參數名)` #### 例3 ```c++ template <typename F, typename T1, typename T2> void call(F f, T1 t1, T2 t2) { //調用前的處理 f(forward<T1>(t1), forward<T2>(t2));//這里已經使用了 std 命名空間 //調用后的處理 } ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看