C++那些细节--函数的默认参数
来源:互联网 发布:淘宝店怎么样提高销量 编辑:程序博客网 时间:2024/06/05 16:59
关于C++函数默认参数的问题,来一个整理。
一.形参&实参
形参和实参,虽然用了这么久了,不过概念上还是有点纠结的。这里简单总结一下:形参是说明参数类型的,实参就是函数实际操作的对象,我们定义一个函数的时候,写的那个是形参,我们调用函数的时候,给如的参数就是实参。
最近在百度知道上看到了一个关于形参实参最精辟的解释,无耻的引用一下:
比如说进女厕所,那就是女人才能进去 ,那么女人就是进女厕所这个操作的形参,林黛玉进去了,杨贵妃进去了,林黛玉,杨贵妃这些就是实参,李隆基要进的话那就类型不符
二.简单使用
C++函数支持默认参数,这是一个很方便的特性。我们在函数声明或者定义的时候,给函数的参数设置一个默认值,当调用时如果不给参数或者给出一部分参数,那么就使用函数设定的默认参数值。先看一个例子:
// C++Test.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;void DefaultArguTest(int arg1, int arg2 = 2, int arg3 = 3){cout<<arg1<<" "<<arg2<<" "<<arg3<<endl;}int _tmain(int argc, _TCHAR* argv[]){//第2,3个参数给出了,则使用参数的值cout<<"No Default argu:"<<endl;DefaultArguTest(1,1,1);//第3个参数没给出,则使用默认值cout<<"Default argu3:"<<endl;DefaultArguTest(1,1);//第2,3个参数都没给出,使用默认值cout<<"Default argu2,3:"<<endl;DefaultArguTest(1);system("pause");return 0;}结果:
No Default argu:
1 1 1
Default argu3:
1 1 3
Default argu2,3:
1 2 3
请按任意键继续. . .
三.注意事项
四.默认参数和函数重载的冲突
// C++Test.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>using namespace std;//函数声明void DefaultArguTest(int arg1 = 1, int arg2 = 2, int arg3 = 3);//重载void DefaultArguTest();int _tmain(int argc, _TCHAR* argv[]){//不给参数DefaultArguTest();system("pause");return 0;}//函数定义void DefaultArguTest(int arg1, int arg2, int arg3){cout<<arg1<<" "<<arg2<<" "<<arg3<<endl;}
错误如下:
error C2668: “DefaultArguTest”: 对重载函数的调用不明确
1> 可能是“void DefaultArguTest(void)”
1> 或 “void DefaultArguTest(int,int,int)”
对于当我们不给参数的时候,默认的DefaultArguTest和无参数的DefaultArguTest都可能被调用,所以就造成了调用不明确的错误。
仔细想一下,为什么C++的默认构造函数在我们自己定义了构造函数就自动不生成了呢?
个人感觉,有可能是害怕我们自己定义构造函数时,如果加上默认参数,那么就和编译器为我们提供的默认构造函数冲突了,为了防止这种隐患,索性如果自己写了构造函数,那就不生成默认构造函数了。
五.覆写函数时不要更换默认参数
// C++Test.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <string>using namespace std;class Base{public:virtual void Print(int i = 1, int j = 2){cout<<"In base: "<<i<<" "<<j<<endl;}};class Child : public Base{//我们覆写带有默认参数的函数,VA插件给出了提醒,这两个值都是有默认参数的void Print(int i /* = 1 */, int j /* = 2 */){cout<<"In Child: "<<i<<" "<<j<<endl;}};int _tmain(int argc, _TCHAR* argv[]){Base* base = new Child();base->Print();system("pause");return 0;}结果:
请按任意键继续. . .
但是,如果我们不信邪,偏偏要给子类加一个不同的默认参数,结果就会大大出乎我们的意料:
// C++Test.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include <iostream>#include <string>using namespace std;class Base{public:virtual void Print(int i = 1, int j = 2){cout<<"In base: "<<i<<" "<<j<<endl;}};class Child : public Base{public://我们手动的将默认参数修改了void Print(int i = 3, int j = 4 ){cout<<"In Child: "<<i<<" "<<j<<endl;}};int _tmain(int argc, _TCHAR* argv[]){//静态绑定cout<<"Static bind:"<<endl;Child* child = new Child();child->Print();//动态绑定cout<<"Dynamic bind:"<<endl;Base* base = new Child();base->Print();system("pause");return 0;}结果:
Static bind:
In Child: 3 4
Dynamic bind:
In Child: 1 2
请按任意键继续. . .
第一个没有问题,子类指针调用子类函数,输出的结果也是子类给出的默认参数。但是,第二个问题就大了,我们明明触发了多态,但是,输出的结果竟然是基类给出的那两个默认参数的值!!!
为什么会这样?因为为了效率,函数的默认参数是使用静态绑定的,换句话说,不管你有没有多态,我只关心你用什么指针来调,基类指针就调用基类的默认参数,子类指针就给出子类的默认参数。而不像我们多态那样,会发生动态绑定,可以用基类指针调用子类函数。而我们在一个动态绑定的函数中使用了静态绑定的参数,结果肯定是不对的!
所以,正如《Effective C++》中所说:“绝不重新定义继承而来的缺省参数”!
- C++那些细节--函数的默认参数
- C++_有默认参数的函数
- 程序猿之---C语言细节27(函数无参数时细节、函数默认返回int型证明、return默认还回值、void指针++操作)
- 3、C函数可变参数实现细节的一些思考
- 函数默认参数(C#)
- C语言 函数默认参数
- 函数的默认参数
- 函数的默认参数
- 函数的默认参数
- 函数的默认参数
- 默认参数的函数
- 函数的默认参数
- 函数的默认参数
- 函数的默认参数
- c++/c中函数默认参数的详细解析
- C++11 学习笔记 模板的细节(右尖括号,using,函数模板默认参数)
- 在C语言中模拟含有默认参数的函数
- C++对C的函数拓展 - 默认参数
- 指针
- 黑马程序员——集合
- gcc与g++
- 矩阵结构体
- Java 线程测试框架
- C++那些细节--函数的默认参数
- hdu 5414 CRB and String 2015多校联合训练赛#10 贪心
- 简单灵活解决 Viewgroup嵌套 产生的手势冲突问题
- SysBench 0.5 安装
- 用C语言编程求三角形的面积
- POJ1008My Calendar两种日历年月日间的转换月份用字符数组表示
- Android组件之间的信使Intent
- 2015.8.20 多校#10 1009 CRB and String
- ppc_85xx-gcc -shared -fPIC liberr.c -o liberr.so