為什么C++函數形參默認值從最末一個賦值?


【1】函數調用時形參的壓棧順序

1、示例代碼如下(VS2010):

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void fun(int a, int b, int c = 100);
 5 
 6 void fun(int a, int b, int c) // 這種情況不可以寫,因為函數聲明已寫
 7 {
 8     cout << "a :: " << a << endl;
 9     cout << "b :: " << b << endl;
10     cout << "c :: " << c << endl;
11 }
12 
13 class A
14 {
15 public:
16     void fun1(int a, int b);
17     void fun2(int b, int c = 100);
18 };
19 
20 void A::fun1(int a, int b = 100)  // 這種情況可以寫
21 {
22 }
23 
24 void A::fun2(int b, int c)  // 這種情況下不可以寫,因為函數聲明已寫
25 {
26 }
27 
28 void main()
29 {
30     int n = 10;
31     fun(n * n, n, n++);
32 
33     system("pause");
34 }
35 
36 // run out:
37 /*
38 a :: 121
39 b :: 11
40 c :: 10
41 請按任意鍵繼續. . .
42 */

分析:

從輸出的結果琢磨,a如果等於10 * 10 = 100,說明是先壓棧參數a。

然后,再壓棧參數b,b = n, 那么b等於10。

最后,再壓棧參數c,c = n++,即c等於10。而n最終等於11。

但是,還得用客觀事實說明問題:

首先,壓棧形參c,c = n++,即c等於10。而n執行完后等於11。

然后,壓棧形參b,b = n,即b等於11。

最后,再壓棧形參a,a = n * n, 即a等於121。

2、有人說還看得不太明白,雲里霧里的。那么請再看如下實例分析。

代碼如下:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 class TestA
 5 {
 6 public:
 7     TestA(int a = 10, int b = 20, int c = 30, int d = 40)
 8         : m_nA(a)
 9         , m_nB(b)
10         , m_nC(c)
11         , m_nD(d)
12     {}
13 
14     int getA() { cout << "TestA::getA() [" << m_nA << "]" << endl;  return m_nA; }
15     int getB() { cout << "TestA::getB() [" << m_nB << "]" << endl;  return m_nB; }
16     int getC() { cout << "TestA::getC() [" << m_nC << "]" << endl;  return m_nC; }
17     int getD() { cout << "TestA::getD() [" << m_nD << "]" << endl;  return m_nD; }
18 
19 private:
20     int m_nA;
21     int m_nB;
22     int m_nC;
23     int m_nD;
24 };
25 
26 int sumFunc(int a, int b, int c, int d)
27 {
28     return (a + b + c + d);
29 }
30 
31 void main()
32 {
33     TestA aObj;
34     cout << "調用順序及求和結果如下:" << endl;
35     cout << sumFunc(aObj.getA(), aObj.getB(), aObj.getC(), aObj.getD()) << endl;
36     system("pause");
37 }
38 
39 // run out:
40 /*
41 調用順序及求和結果如下:
42 TestA::getD()[40]
43 TestA::getC()[30]
44 TestA::getB()[20]
45 TestA::getA()[10]
46 100
47 請按任意鍵繼續. . .
48 */

 通過調用全局函數sumFunc,分析其形參的壓棧先后順序。

【2】為什么函數形參默認值需要從最后一個賦值?

從上一步的研究結果發現:

函數調用時,首先壓棧最后一個形參,若有一個已經確定默認值或常規調用可以忽略除非在特殊情況下才考慮的形參,那么置為最末一個形參。

建議在聲明函數時,最好加上默認值。定義函數時,不需要再加默認值(因為編譯器會報重定義默認參數值的編譯錯誤)。

(備注:其實,聲明不加定義加也行,但是為了便於代碼的閱讀與維護,建議聲明加定義不加。)

反證法。假設不從最后一個賦默認值,那么試想一下,編譯器就會匹配不到最后一個形參的值,報編譯錯誤。

【3】總結

壓棧形參由后向前,賦默認值也應由后向前。

 

Good Good Study, Day Day Up.

順序 選擇 循環 總結


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM