【1】函数调用时形参的压栈顺序

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

 #include <iostream>
using namespace std; void fun(int a, int b, int c = ); void fun(int a, int b, int c) // 这种情况不可以写,因为函数声明已写
{
cout << "a :: " << a << endl;
cout << "b :: " << b << endl;
cout << "c :: " << c << endl;
} class A
{
public:
void fun1(int a, int b);
void fun2(int b, int c = );
}; void A::fun1(int a, int b = ) // 这种情况可以写
{
} void A::fun2(int b, int c) // 这种情况下不可以写,因为函数声明已写
{
} void main()
{
int n = ;
fun(n * n, n, n++); system("pause");
} // run out:
/*
a :: 121
b :: 11
c :: 10
请按任意键继续. . .
*/

分析:

从输出的结果琢磨,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、有人说还看得不太明白,云里雾里的。那么请再看如下实例分析。

代码如下:

 #include <iostream>
using namespace std; class TestA
{
public:
TestA(int a = , int b = , int c = , int d = )
: m_nA(a)
, m_nB(b)
, m_nC(c)
, m_nD(d)
{} int getA() { cout << "TestA::getA() [" << m_nA << "]" << endl; return m_nA; }
int getB() { cout << "TestA::getB() [" << m_nB << "]" << endl; return m_nB; }
int getC() { cout << "TestA::getC() [" << m_nC << "]" << endl; return m_nC; }
int getD() { cout << "TestA::getD() [" << m_nD << "]" << endl; return m_nD; } private:
int m_nA;
int m_nB;
int m_nC;
int m_nD;
}; int sumFunc(int a, int b, int c, int d)
{
return (a + b + c + d);
} void main()
{
TestA aObj;
cout << "调用顺序及求和结果如下:" << endl;
cout << sumFunc(aObj.getA(), aObj.getB(), aObj.getC(), aObj.getD()) << endl;
system("pause");
} // run out:
/*
调用顺序及求和结果如下:
TestA::getD()[40]
TestA::getC()[30]
TestA::getB()[20]
TestA::getA()[10]
100
请按任意键继续. . .
*/

通过调用全局函数sumFunc,分析其形参的压栈先后顺序。

【2】为什么函数形参默认值需要从最后一个赋值?

从上一步的研究结果发现:

函数调用时,首先压栈最后一个形参,若有一个已经确定默认值或常规调用可以忽略除非在特殊情况下才考虑的形参,那么置为最末一个形参。

建议在声明函数时,最好加上默认值。定义函数时,不需要再加默认值(因为编译器会报重定义默认参数值的编译错误)。

(备注:其实,声明不加定义加也行,但是为了便于代码的阅读与维护,建议声明加定义不加。)

反证法。假设不从最后一个赋默认值,那么试想一下,编译器就会匹配不到最后一个形参的值,报编译错误。

【3】总结

压栈形参由后向前,赋默认值也应由后向前。

Good Good Study, Day Day Up.

顺序 选择 循环 总结

为什么C++函数形参默认值从最末一个赋值?的更多相关文章

  1. ES6学习 --函数参数默认值与解构赋值默认值

    1. ES6的解构ES6中引入了解构赋值的操作,其作用是:将值从数组Array或属性从对象Object提取到不同的变量中 即分为两种情况:从数组Array中解构,以及从对象Object中解构 ①.从数 ...

  2. ES6函数参数默认值作用域的模拟原理实现与个人的一些推测

    一.函数参数默认值中模糊的独立作用域 我在ES6入门学习函数拓展这一篇博客中有记录,当函数的参数使用默认值时,参数会在初始化过程中产生一个独立的作用域,初始化完成作用域会消失:如果不使用参数默认值,不 ...

  3. 函数的默认值与动态参数arguments的总结

    在js函数与作用域,了解函数基本概念中,我们发现当函数的实参有一个没有上传的时候,对应的形参time展示的值就是undefined,如下代码所示: <!DOCTYPE html> < ...

  4. 【C#基础概念】函数参数默认值和指定传参和方法参数

    函数参数默认值和指定传参 最近在编写代码时发现介绍C#参数默认值不能像PL/SQL那样直接设置default,网上也没有太多详细的资料,自己琢磨并试验后整理成果如下: C#允许在函数声明部分定义默认值 ...

  5. 问题:C++形参默认值为什么一定要放在最后?

    问题:C++形参默认值为什么一定要放在最后? 1.会出现歧义! 2.从汇编角度看是怎么回事?   待解答!!

  6. Python函数参数默认值的陷阱和原理深究"

    本文将介绍使用mutable对象作为Python函数参数默认值潜在的危害,以及其实现原理和设计目的 本博客已经迁移至: http://cenalulu.github.io/ 本篇博文已经迁移,阅读全文 ...

  7. java函数参数默认值

    java函数参数默认值 今天,需要设定java函数参数的默认值,发现按照其它语言中的方法行不通 java中似乎只能通过函数的重载来实现 函数参数默认代码

  8. Python函数参数默认值的陷阱和原理深究(转)

    add by zhj: 在Python文档中清楚的说明了默认参数是怎么工作的,如下 "Default parameter values are evaluated when the func ...

  9. php函数指定默认值的方法

    发布:JB02   来源:脚本学堂     [大 中 小] 本文介绍下,在php编程中,指定函数的默认值的方法,分享二个例子,供大家学习参考下.本文转自:http://www.jbxue.com/ar ...

随机推荐

  1. MovieLens电影数据分析

    下载数据包 链接:https://grouplens.org/datasets/movielens/1m/ 解压: 四个文件分别是数据介绍,电影数据表,电影评分表,用户表 进行电影数据分析 进入ipy ...

  2. 注解之@PathVariable

    @PathVariable只支持一个属性value,类型是为String,代表绑定的属性名称.默认不传递时,绑定为同名的形参. 用来便捷地提取URL中的动态参数.其英文注释如下: Annotation ...

  3. oracle创建表空间 授权

    --创建表空间 临时表空间 create temporary tablespace xiaodai_temp tempfile '/main/app/oracle/oradata/devdb/xiao ...

  4. CentOS安装HBase

    1.下载HBASE http://www.apache.org/dyn/closer.cgi/hbase/ 2.解压文件到安装目录 #mkdir hbase #cd hbase #tar -zxvf ...

  5. 如何在js中将统计代码图标隐藏

    建站时我们都会加一下网站统计,方便把控内容的内容的运营.大部分站长安装的站点统计是第三方统计代码,js形式的,很少用以服务器日志为基础分析的统计.(当然能通过网站日志来分析网站的运营者比一般的站长水平 ...

  6. Unable to cast COM object of type 'Shell32.ShellClass' to interface type 'Shell32.IShellDispatch6'.

    VS 里面的Interop.Shell32.dll(1.0) 这个版本太低了,需要高版本的(我使用的是1.2.107.0) 具体下载地址  自己找吧

  7. Linux下的python等操作【转载】

    转自:https://blog.csdn.net/healthy_coder/article/details/50546384 https://blog.csdn.net/boyun58/articl ...

  8. 配置android.support.v7.widget.Toolbar 搜索框样式

    AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xm ...

  9. 2018-2019-1 20189221《Linux内核原理与分析》第三周作业

    2018-2019-1 20189221<Linux内核原理与分析>第三周作业 实验二 完成一个简单的时间片轮转多道程序内核代码 实验过程 在实验楼中编译内核 编写mymain.c函数和m ...

  10. 《全栈性能Jmeter》-2性能测试初体验