个人主页:PingdiGuo_guo
收录专栏:C++干货专栏
前言
本篇博客是讲解函数的重载以及引用的知识点的。
文章目录
前言
1.函数重载
1.1何为函数重载
1.2函数重载的作用
1.3函数重载的实现
2.引用
2.1何为引用
2.2定义引用
2.3引用特性
2.4常引用
2.5使用场景
2.6传值、传引用的效率对比
2.6.1作为参数
2.6.2作为返回值
2.7引用和指针的区别
2.7.1汇编层面
2.7.2语法
总结
1.函数重载
重载是指在同一作用域内,允许定义多个相同名称的函数或方法,但它们的参数列表不同。在调用时,根据参数的数量和类型的不同,编译器会自动选择匹配的函数或方法进行调用。
1.1何为函数重载
函数重载是指在同一个作用域内,允许定义多个函数,它们具有相同的名称但参数列表不同。当调用这个函数时,编译器通过参数的数量、类型或顺序来确定具体调用哪个函数。这样可以根据不同的参数类型或个数来实现同一个功能的不同实现方式。
1.2函数重载的作用
函数重载的主要作用有:
1. 方便使用:通过函数重载,可以使用同一个函数名来表示具有相似功能的函数,提高了函数的可读性和可理解性。
2. 简化编程:函数重载可以简化程序的编写,因为不需要为相似的功能编写不同的函数名,只需要在参数列表中添加不同的参数来区分不同的函数。
3. 提高代码复用性:通过函数重载,可以将相似功能的代码封装在同一个函数中,提高代码的复用性和维护性。
4. 适应不同的数据类型和参数个数:函数重载允许在不同的函数中使用不同的数据类型和参数个数,使函数可以处理不同类型和不同数量的数据。
总之,函数重载提供了一种更灵活和方便的程序设计方式,使函数的使用更加简单和高效。它是一种提高程序可读性、可维护性和可扩展性的重要手段。
1.3函数重载的实现
函数重载分好几种:
1.参数类型不同
#include<bits/stdc++.h>
using namespace std;
//参数类型不同
int da(int s,int a)
{
cout<<a<<endl;
return 0;
}
int da(int s,char a)//ok?
{
cout<<a<<endl;
return 0;
}
int main()
{
int s=1,a=2;
char b='4';
//组一
cout<<"1:"<<endl;
da(s,a);
da(s,b);
return 0;
}
运行结果:
2.参数个数不同
#include<bits/stdc++.h>
using namespace std;
//参数个数不同
int ta(int s,int b,int a)
{
cout<<b<<endl;
return 0;
}
int ta(int s,int a)//ok?
{
cout<<a<<endl;
return 0;
}
int main()
{
int s=1,a=2;
int b=4;
//组二
cout<<"2:"<<endl;
ta(s,b,a);
ta(s,a);
return 0;
}
运行结果:
3.参数类型顺序不同
#include<bits/stdc++.h>
using namespace std;
//参数类型顺序不同
int ea(int a,char s)
{
cout<<a<<endl;
return 0;
}
int ea(char s,int a)
{
cout<<a<<endl;
return 0;
}
int main()
{
int s=1,a=2;
char b='4';
//组三
cout<<"3:"<<endl;
ea(a,b);
ea(b,a);
return 0;
}
运行结果:
2.引用
2.1何为引用
在C++编程语言中,引用概念是一种用于创建别名的机制。通过引用,可以使用一个变量或对象的别名来访问它。
例如,小刘的小名是纯纯,那我们既可以叫他小刘,也可以叫他纯纯。
2.2定义引用
定义引用的语法:
<数据类型> &<引用变量名> = <已存在的变量名>;
以下是一个完整的C++代码示例:
#include <iostream>
using namespace std;
int main() {
int a = 10;
int& b = a; // 定义一个整型引用b,它是a的别名
cout << "a: " << a << endl; // 输出原始的变量a的值
cout << "b: " << b << endl; // 输出引用b的值
b = 20; // 修改引用b的值,也会影响到变量a的值
cout << a << endl; // 输出修改后的变量a的值
return 0;
}
在上述代码中,变量a是一个整型变量,而引用b是对a的引用。通过输出语句可以看到,变量a和引用b的初始值是相同的,而修改引用b的值后,变量a的值也相应改变。我们定义引用,相当于给变量或对象起了一个别名。
2.3引用特性
引用在定义时必须初始化
一个变量可以有多个应用
引用一旦引用一个实体,就不能再引用其他实体
#include <iostream>
using namespace std;
int main()
{
int a = 1;
//int& b;//引用未初始化
int& c = a;//多个引用
int& d = a;
cout<<&c<<' '<<&d<<endl;
return 0;
}
运行结果:
2.4常引用
#include <iostream>
using namespace std;
int main()
{
const int a = 1;
//int& s=a;//ok?
//int& b = 10;//ok?
const int& b = 10;
float c;
//int& n=c;//ok?
return 0;
}
运行结果:
这里都不能运行,a为常量,无法运行,b为常量,无法运行,c和n类型不同,无法运行。
2.5使用场景
C++中引用的使用场景包括以下几个方面:
1. 函数参数传递:通过引用将参数传递给函数,在函数内部修改参数的值,可以直接对原始变量进行操作,避免了拷贝带来的额外开销。
void swap(int& a, int& b) {
int temp = a;
a = b;
b = temp;
}
int main() {
int x = 1, y = 2;
swap(x, y);
return 0;
}
2. 函数返回值:可以通过引用返回函数内部的局部变量,避免了拷贝带来的开销。
int& max(int& a, int& b) {
return a > b ? a : b;
}
int main() {
int x = 1, y = 2;
int& result = max(x, y);
return result;
}
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回;如果已经返还给系统,则必须使用值传递。即返回的实体必须要比函数的生命周期长,不能返回函数栈上的空间。在使用引用时要确保引用的对象存在,引用不能引用空指针。
2.6传值、传引用的效率对比
以值作为参数或者返回值类型,在传值和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者返回值类型,效率是非常低的,尤其是当参数或者返回值类型非常大时,效率就更低。
2.6.1作为参数
代码来啦:
#include <bits/stdc++.h>
struct B{ int a[10000]; };
void TestFunc1(B a){}
void TestFunc2(B& a){}
void TestRefAndValue()
{
B a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(B)-time:" << end1 - begin1 << '\n';
cout << "TestFunc2(B&)-time:" << end2 - begin2 << '\n';
}
运行结果:
解释:大家可以看到,传引用的效率要“更上一层楼”,但为什么这里的传引用的时间是“0”呢?这是因为它的运行时间太短了,小于1毫秒,所以显示为“0”。
2.6.2作为返回值
代码来啦:
#include <bits/stdc++.h>
struct B{ int a[10000]; };
B a;
// 值返回
B TestFunc1() { return a;}
// 引用返回
B& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << '\n';
cout << "TestFunc2 time:" << end2 - begin2 << '\n';
}
运行结果:
解释:可以看出作为返回值效率更高。
2.7引用和指针的区别
2.7.1汇编层面
在汇编层面上,引用和指针之间的主要区别在于它们在内存中的表示和使用方式。
1. 引用:在汇编层面上,引用通常被实现为指针。当引用被创建时,编译器会将引用作为指针来处理,即将引用的名称作为一个指向所引用对象内存地址的指针。因此,引用在汇编层面上可以通过该指针来访问所引用的对象。与指针不同的是,引用在声明时必须初始化,并且无法更改引用的目标对象。
2. 指针:在汇编层面上,指针直接表示一个内存地址。指针变量存储了所指向对象在内存中的地址。通过加载和存储指令,可以使用指针来访问所指向的对象。与引用不同,指针可以被重新赋值,即指向不同的对象。
在使用引用和指针时,编译器在汇编层面上会生成不同的指令来处理对引用和指针的操作。引用的访问通常会被转换为加载和存储指令,而指针的访问可能会涉及更多的指针运算,如加法和减法操作。
2.7.2语法
1. 声明和初始化:在声明引用时,必须同时进行初始化。例如:int& ref = variable;,其中ref是一个引用,它被初始化为variable。而指针的声明可以先进行,然后再进行初始化,也可以不进行初始化。例如:int* ptr = nullptr;,其中ptr是一个指针,它被初始化为nullptr。
2. 语法符号:引用使用&符号进行声明和引用操作,例如:int& ref = variable;。指针使用*符号进行声明和解引用操作,例如int* ptr = &variable;。
3. 空值和空引用:指针可以被赋予空值(nullptr),表示指针不指向任何有效的内存地址。引用则不允许为空,必须在声明时进行初始化,并且只能引用有效的内存地址。
4. 变量的地址:引用本身没有独立的内存地址,它只是已存在变量的一个别名。而指针是一个变量,它存储了所指向对象在内存中的地址。
5. 内存操作:通过引用操作所引用的变量,可以直接修改引用所指向的内存内容。而通过指针,可以通过解引用操作修改所指向的内存内容。
总的来说,引用必须进行初始化,不能为null,没有独立的内存地址;而指针可以先声明再初始化,可以为null,有自己独立的内存地址。
总结
本篇博客到这里就结束了,制作不易,还是希望大家点赞支持,谢谢大家!