十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
函数重载:是函数的一种特殊情况,C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的 形参列表(参数个数 或 类型 或 顺序)必须不同,常用来处理实现功能类似数据类型不同的问题。
创新互联公司是一家专注网站建设、网络营销策划、成都小程序开发、电子商务建设、网络推广、移动互联开发、研究、服务为一体的技术型公司。公司成立十余年以来,已经为千余家成都发电机维修各业的企业公司提供互联网服务。现在,服务的千余家客户与我们一路同行,见证我们的成长;未来,我们一起分享成功的喜悦。int add(int a, int b, int c)
{
return a+b+c;
}
int add(int a, int b)
{
return a+b;
}
int main()
{
add(1,2,3);
add(1,2);
return 0;
}
思考下面一段代码,下面两个函数是否属于函数重载,他们有没有什么问题?
int func()
{
return 0;
}
int func(int a=10)
{
return a;
}
int main()
{
func();
func();
return 0;
}
根据定义,函数名相同参数不同,他们当然构成重载函数,虽然他们构成重载函数,但是在使用时会有问题,因为调用函数时存在二异性。应该避免这种情况出现。
函数重载原理先大概了解编译器编译程序过程(Linus下),现在有test. c、func.c、func.h三个文件。
1.预处理阶段,func.h头文件被展开、然后进行宏替换、条件编译、去注释。生成func.i和test.i两个文件。
2.编译阶段,检查语法,生成汇编代码。生成func.s和test.s文件。
3.汇编,汇编代码转化为二进制机器码,形成符号表。生成func.o和test.o文件。
4.链接,文件在链接阶段被分成几段进行操作。先进行合并段表,把相关文件对应的段连接到一起,然后对符号表进行合并和重定向。生成func.o和test.o链接生成a.out文件。
C语言不支持函数重载,因为编译时两个重载函数函数名相同,在func.o符号表中存在歧义和冲突,其次链接时也有冲突,因为C语言中是直接使用函数名标识和查找。
而C++的目标文件符号表中不是直接使用函数名来标识和查找函数,它引入了函数名修改规则,通过参数的属性修改函数名。前面提到C++中函数重载的概念中必须有参数个数 或 类型 或 顺序的不同,通过这三种参数属性修改了函数名,不同编译器的修改规则不同。Linus下修饰规则为_Z+函数长度+函数名+参数类型首字母。
通过这里我们就明白了为什么C语言不支持函数重载,因为同名函数无法区分,而C++使用函数修改规则通过参数的不同属性改变了函数名,从而就能支持重载。
二、引用 概念引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。类型&引用变量名(对象名)=引用实体。引用在语法层没有开辟新空间,相当于给原变量起一个新名称。下图我们会发现a和b的地址一样。
#includeusing namespace std;
int main()
{
int a = 10;
int& b = a;
system("pause");
return 0;
}
引用的特性1.引用在定义时必须初始化。
void test()
{
//int& b;//编译会出错
}
2.一个变量可以有多个引用。
void test()
{
int a=10;
int& b=a;
int& c=a;
int& d=b;
}
3.引用一旦引用一个实体,再不能引用其他实体。
void test()
{
int a=10;
int& b=a;
int c=15;
b=c;//这里不是b引用c,而是把c的值赋给b,要和指针的使用区分
}
引用的使用1.引用做参数,功能与传指针参数类似。
//传指针
void swap(int* x,int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
//传引用
void swap(int& x,int& y)
{
int tmp=x;
x=y;
y=tmp;
}
int main()
{
int a=10;
int b=20;
swap(&a,&b);
swap(a,b);
return 0;
}
2.引用做返回值
在传值返回的函数中,因为函数执行完成后函数栈帧已经被销毁,会非法访问返回的变量,所以返回的值需要先存储在临时变量中。如果返回的对象较小不大于八个字节,一般是寄存器充当临时变量,如果比较大则存放在调用函数的栈帧内。所有的传值返回都会生成一个拷贝,当返回的数据量很大时使用引用做返回值效率会提高。
传值返回:
下面这段代码存在非法访问的问题,add函数的返回值是变量c的引用,当函数执行完成栈帧销毁后,访问了c的空间,如果add函数栈帧销毁时清理空间,那么取c值时取到的就是随机值。
#includeusing namespace std;
int& add(int x, int y)
{
int c = x + y;
return c;
}
int main()
{
//非法访问c的空间
int ret = add(10, 20);
return 0;
}
上面的例子是一个错误的用法,那么该如何使用引用返回?如果函数返回时,出了函数作用域,如果返回的对象还在(静态变量、全局变量等),则可以使用引用返回,否则必须使用传值返回。
#includeusing namespace std;
int& add(int x, int y)
{
static int c = x + y;
return c;
}
int main()
{
int ret = add(10, 20);
return 0;
}
总结引用的作用主要体现在传参和传返回值
1.引用传参和引用传返回值在有些场景下可以提高性能(大对象+深拷贝对象)
2.引用传参和引用传返回值做输出型参数和输出型返回值。有些场景下形参的改变可以改变实参,引用返回可以改变返回对象。
常引用int main()
{
const int a=10;
int& b=a;//权限的放大,编译会出错,a只读而b可写
const int& b=a;//权限不变,可编译通过
int c=10;
const int& d=c;//权限的缩小,编译可以通过
return 0;
}
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧