• 为什么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.

    顺序 选择 循环 总结

  • 相关阅读:
    js+servlet实现百度搜索栏下拉框的实现
    python time模块
    dajngo基础
    MySQL解决时区问题:datadrip com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized or represents more than one time zone.
    数据库连接池
    超星学习通绕开鼠标监控的方法
    centos7 安装python3
    docker命令
    爬虫一
    学习python的第九天笔记
  • 原文地址:https://www.cnblogs.com/Braveliu/p/6616853.html
Copyright © 2020-2023  润新知