C++引用与函数提高
对象new不出来 人气:0详解引用
引用的基本使用
语法:数据类型 &新变量名 =原来变量名
作用:给变量起别名
注意事项:
1、引用必须初始化
2、一旦初始化就不能更改(具体原因在下面引用本质上会讲到)
示例:
int a = 10; int c = 20;
如果写 int &b;
这是错误的,没有初始化引用,编译器不知道b指向的地址。
所以这样写 int &b=a;
那么现在b是a 的别名,他们的地址相同,存放的数据也都一样。这时如果写 b=c;我们不会认为 b是c的别名,只会认为是把c的值赋给了b,当然也赋给了a
引用做函数参数
这是引用最为方便和精辟的地方了,直接代替指针来进行引用传递,我们举个最为经典的例 子:swap交换函数.
void swap(int &x,int &y) { int t = a; a = b; b = t; cout << "swap03 a =" << a << endl; cout << "swap03 b =" << b << endl; } int main() { int a = 10, b = 20; /*值传递形参不能修饰实参 地址传递可以修饰实参*/ swap(a, b);//引用做函数参数也可以修饰实参 }
这里主函数传的实参是a,b 形参是int &x,int &y;
不就是int &x= a, int &y= b
吗,x和a地址相同,y和b地址相同,x和y的变化必会导致a,b的变化,因此属于地址传递,不会令编译器产生副本,节省空间的同时,代码也更简洁。
引用做函数返回值
我们知道函数语法第一个就要写函数返回值类型,在数据类型后加上&符号,就可以返回该函数的引用,有的也叫返回函数的地址,其实意思都一样,只是叫法不同罢了。
注意事项:
1、不要返回局部变量的引用
2、返回函数的引用可以作为左值
示例:
#include<iostream> using namespace std; int& func1() { int a = 10;//局部变量放在四区中的栈区,返回后会被编译器自动销毁 return a; } int& func2() { static int a = 10; return a; } int main() { int& ref1 = func1(); int& ref2 = func2(); cout << "a =" << ref1 << endl; cout << "a =" << ref1 << endl;//乱码 cout << "a =" << ref2 << endl; func2() = 1000;//如果函数的返回值是引用,那这个函数调用可以作为左值 cout << "a =" << ref2 << endl; }
func1函数开辟在栈区,返回的引用会被编译器自动释放掉,main函数中我用&ref1作为func1的引用返回,并输出ref1的值,不出意外,第二次输出的时候会出现乱码,其实就是ref的新地址,func1返回的地址已经被释放掉,第一次能输出是因为编译器做出了保留。func2虽然也是开辟在栈区,但是a 的地址却是放在了全局区,由操作系统自动释放,所以返回func2的引用不会被编译器释放,而且可以作为左值变化数据,最后一个cout结构必当是1000,附上结果图。
常量引用
这个就好理解了,就是传参的时候加上const关键字,防止误操作
示例:
//打印数据函数
void showData(const int& a) {
//a=100; 这里不能做出修改,防止误操作
cout << "a=" <<a<< endl;
}
引用的本质
引用的本质是一个指针常量
编译器发现是“引用”自动将int &ref=a;
转变为 int *const ref=&a;
并且再给 ref赋值时,自动解引用 ref=100 改为 *ref = 100
示例:
void fun1(int &ref) //自动转变为 int *const ref=&a
{
ref = 100; //转换成*ref=100
}
C++推荐使用引用,因为引用的本质是指针常量,但是有关指针的操作编译器都帮我们做了
函数提高
学习C很快就会接触函数了,这里主要讲你少见的函数形式来做一个函数提高
函数默认值
语法:返回类型值 函数名 (形参=默认值){}
注意事项
1、如果某个位置已经有默认参数,那么从这个位置开始从左往右都要有默认值
2、声明和实现只能有一个有默认参数,如果声明的时候给了形参默认值,那么下面对函数的实现就不能再给该形参默认值
示例:
int fun1(int a, int b, int c=50); int fun1(int a, int b, int c) { return a + b + c; } int main() { cout << fun1(10,30) << endl; }
这里cout的结果我们都能猜到是90;如果我们修改代码给形参b默认值,而不给c默认值,就会违反第一个注意事项,这时给c也默认值就解决问题了。
函数占位参数
语法:返回值类型 函数名(数据类型){}
占位参数可以有默认参数:
void fun2(int a,int=20)
{
cout << a<<"is this is fun2" << endl;
}
调用:
fun2(10);
结果:
10is this is fun2
函数重载及注意事项
函数重载需要函数都在一个作用域下
函数名相同,提高复用性
函数参数类型不同 或者 个数不同 顺序不同
#include<iostream> using namespace std; void func() { cout << "func 的调用" << endl; } void func(int a) { cout << "func(int a)的调用" << endl; } void func(double a) { cout << "func(double a)的调用" << endl; } void func(int a, double b) { cout << "func(int a,double b)的调用" << endl; } void func(double b,int a) { cout << "func(doubel b,int a)的调用" << endl; } //函数返回值不可以做重载条件 int main() { func(); func(10); func(12.3); func(10,20.1); func(30.1,20); }
这里写五个func函数,四个重载,并配上提示助理解,输出结果如下:
函数重载注意事项:
1、引用可作为重载的条件
void funct(int& a) { cout << "funct(int &a)的调用" << endl; } void funct(const int& a) { cout << "funct(const int &a)的调用" << endl; }
调用方法:int a = 10; funct(a); funct(20);
重载时加上const 关键字就相当于是一个常量,调用的时候直接写入数据即可。
2、函数重载碰到默认参数
void func2(int a,int b=10) { cout << "func(int a,int b)的调用" << endl; } void func2(int a) { cout << "func(double a)的调用" << endl; }
这里调用func2方法必然会报错,因为两个函数发生了重载,而且调用方法一致,都是
func2(数值);
那么就会产生二义性,编译器无法识别调用的是哪个重载的方法。
加载全部内容