C++ 学习_函数重载和默认参数
我为什么要写C++系列博文呢?理由很蛋疼,因为C++的语法太庞杂了,从目前来看,后面我很难有精力和能力来总结一篇令我满意的”C++语法汇总”,所以干脆放弃那样做,将我学习的过程记录下来,这样写出来的东西包含的知识也比较全面。不过,由于我是学习的过程,所以在文章中难免有一些错误或者疏漏之处,希望大家不嫌麻烦的可以指出我的错误,本人会在第一时间修正该系列内容!
最后注:本系列博文会持续更新,并不断修正部分内容,希望关注的朋友可以一直看完,相信一定会有所收获,或者有所思考。。。
一、函数的默认参数
下面是封装的一个申请内存的函数,默认每次申请100字节的内存:
void* GetMemory(int bytesize = 100)
{
return malloc(bytesize);
}
函数默认参数的作用:
- 如果这个函数需要多次使用相同的参数,采用默认参数会很方便(主要)
- 避免因为多次书写而手误写错(次要)
- 有些时候,对于调用的函数 ,刚开始可能不清楚或者不关心传递什么值 ,就给一个默认值先让代码跑起来 ,后续发现不合适了,再来重新设置
注意:
1. 缺省参数是作为实参传递给函数的,而不是在函数内部直接使用的
2. 若函数所有形参均有缺省值,则称为全缺省。传参时可以传(<=形参数目)个参数。从表面上看起来,像是从左往右依次赋值。
注:c/c++在默认情况下,函数的调用约定都是_cdecl,而这种调用约定规定:函数的参数是从右往左依次来传递的 所以在接收用户参数时,也是从右往左来传递的。
结合下面这个例子理解第二条:
假设现在有一个半缺省参数的函数,Fun(int a, int b = 10, int c = 20) 在调用时候 Fun(30) 这个30最后会传递给a。为什么传递给a ?是因为编译器在编译时会进行检测 Fun实际上有三个参数 ,而调用时只传递了一个 ,那编译器就会对函数的参数进行检查,看是否有缺省参数, 如果有后两个参数就使用缺省值了,我们传递的30就只能给a了,如果没有缺省参数,就会报错
若不是全缺省,则在设计函数形参的缺省值时,只能从右往左依次设定。
原因:若缺省参数右边还有未设置缺省值的参数,出现下面这种情况就会有歧义:void Func(int a=1,int b);
void main( void )
{
Func();//错误,因为b未赋实参
Func(1);//错误,因为1赋给了a(左->右),b未赋实参
}- 缺省值只能放在函数声明/定义其中一个位置来设置,不能在这两个地方同时设置。
注:建议将其放到声明的位置来设置(头文件中)。原因:当你写了一个库,编译后生成静态库(静态库中都是二进制文件,一般不可读),当别人想要用你的库,但是你又不想泄露源代码,就可以将头文件和静态库给他,头文件作为静态库的说明,而头文件中如果不包含函数缺省值的说明,对方就无法正确的使用你定义的函数缺省参数,所以建议将缺省值放到函数声明处设置,一般函数声明都放在头文件。
不能同时设置的原因:若因为意外使得声明和定义处的函数缺省值不同,就会出现歧义(编译器就不知道使用哪个缺省值)- 缺省值只能放在函数声明/定义其中一个位置来设置,不能在这两个地方同时设置。
- 缺省值只能是常量或者全局变量。
二、函数重载
1. 要求(除此之外均不构成函数重载):
1. 重载函数必须在同一作用域内
2. 重载函数名必须相同
3. 形参列表必须不同(个数 / 类型 / 参数类型顺序)
2. 函数重载实例:
//重载加法函数(整形和浮点型)
int add(int num1,int num2)//函数1
{
return num1+num2;
}
double add(double num1,double num2)//函数2
{
return num1+num2;
}
void main( void )
{
int num1=1,num2=2,num3;
double num4=2.3,num5=1.2,num6;
num3=add(num1,num2);//调用函数1
num6=add(num4,num5);//调用函数2
}
3. 为什么C语言不支持重载?
C++和C语言的编译方式不同。 C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func() 编译后为 func() 或 _func()。
而C++中的函数在编译时会根据它所在的命名空间、它所属的类、以及它的参数列表(也叫参数签名)等信息进行重新命名,形成一个新的函数名。这个新的函数名只有编译器知道,对用户是不可见的。对函数重命名的过程叫做名字编码(Name Mangling),是通过一种特殊的算法来实现的。
Name Mangling 的算法是可逆的,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推演出原有函数名。Name Mangling 可以确保新函数名的唯一性,只要函数所在的命名空间、所属的类、包含的参数列表等有一个不同,最后产生的新函数名也不同。
下面是一个测试用例:
#include <iostream>
using namespace std;
void display();
void display(int);
namespace ns{
void display();
}
class Demo{
public:
void display();
};
int main()
{
display();
display(1);
ns::display();
Demo obj;
obj.display();
return 0;
}
该例中声明了四个同名函数,包括两个具有重载关系的全局函数,一个位于命名空间 ns 下的函数,以及一个属于类 Demo 的函数。它们都是只声明而未定义的函数。
在VS下编译后就会看到下面的信息,不同的编译器有不同的 Name Mangling 算法,产生的函数名也不一样。:
4. Else:
C++的函数可以在C环境编译,但是无法运行,如果要运行,可以采用下面的方法:
在函数名前加 extern “C” ,即按C风格编译这些函数,下面是一个使用的实例:
int add(int a,int b);//不可以运行
extern "C" int add(int a,int b);//可以运行
还可以这样:
extern "C"{
函数1;
函数2
……
}
其他知识点:
1. 传值调用和传址调用
- 传值调用
- 缺点:不能通过修改参数来改变外部实参
- 优点:函数的副作用不会影响外部实参
- 传址调用
- 优点:节省空间,效率高,在函数内部操作可以作用于函数外部
- 缺点:不安全
2. 浮代中的小数默认为double,若需指定为float型,需要在其后加上f.
eg:
1.0//double型
1.0f//float型
遗留问题:
1. 面向对象和面向过程的区别
2. extern和static的详细资料