引用是已经定义的变量的别名,改变别名其实也是改变变量的本身;
下面看看最基本的引用将会用到哪里——交换变量
swap(int *a,int *b)//指针引用解除引用交换变量
{
*a=*a^*b;
*b=*a^*b;
*a=*a^*b;
}
swap(int &a,int &b)//这里是通过引用传递
{
a=a^b;
b=a^b;
a=a^b;
}
实际代码如下
#include<iostream>
using namespace std;
void swapr(int *a,int *b)//指针引用解除引用交换变量
{
*a=*a^*b;
*b=*a^*b;
*a=*a^*b;
}
void swapt(int &m,int &n)//这里是通过引用传递
{
m=m^n;
n=m^n;
m=m^n;
}
int main(void)
{
int a=10,b=100;
swapr(&a,&b);
cout<<a<<" "<<b<<endl;
swapt(a,b);
cout<<a<<" "<<b<<endl;
return 0;
}
100 10
10 100
1.创建引用变量
c和c++使用&作为取地址符来指示变量的地址。在c++中它还有另外一个含义,将其用来声明引用,如上述解释。
例如:将rodents作为变量rats的别名,可以
int rats;
int &rodents=rats;
在这里&不是取地址符而是类型标识符的一部分。就像声明中的char *指的是指向char的指针一样。int &指的是指向int 的引用。上述引用声明的变量他们都指向相同的值和内存单元。
2.例子(包括引用变量作为函数参数和创建引用变量)
//c++将引用用于结构
#include<iostream>
#include<string>
struct free_throws//定义一个结构体
{
std::string name;//名字
int made;
int attempts;
float percent;
};
void display(const free_throws &ft);
//这里的引用变量是不可变的,次函数的作用就是输出结构里的所有成员变量
void set_pc(free_throws & ft);
//计算
free_throws & accumulate(free_throws & target,const free_throws & source);
int main()
{//在c++里定义一个结构体变量是不需要struct定义的(省略了)
free_throws one ={"ifelsa branch", 13, 14};//赋值
free_throws two ={"andor knott", 10, 16};
free_throws three={"minner max", 7, 9};
free_throws four={"whily looper", 5, 9};
free_throws five={"long long", 6, 14};
free_throws team={"throwgoods", 0, 0};
free_throws dup;
set_pc(one);//算出来第一个的percent
display(one);//将他输出
accumulate(team,one);//叠加,积累两个结构体成员变量中的值
display(team);//输出
display(accumulate(team,two));//展示与display(team)等效
accumulate(accumulate(team,three),four);//将three与team叠加完之后,再与four叠加
display(team);//team就是叠加完之后那个
dup=accumulate(team,five);//结构体之间是可以赋值的
std::cout<<"displaying team:\n";
display(team);//输出team与上述dup是相同的
std::cout<<"displaying dup after assignment:\n";
display(dup);//输出dup检测一下
set_pc(four);//把four的percent算出来
accumulate(dup,five) =four;//赋值
std::cout<<"displaying dup after ill_advised assignment:\n";
display(dup);
return 0;
}
void display(const free_throws & ft)//显示结构的内容但是不修改它,加上const修饰
{
using std::cout;//只是方便一下输出
cout<<"name: "<<ft.name<<'\n';
cout<<" made : "<<ft.made<<'\t';
cout<<"attempts: "<<ft.attempts<<'\t';
cout<<"percent: "<<ft.percent<<'\n';
}
void set_pc(free_throws & ft)
{
if(ft.attempts!=0)//计算百分比判断分母是否为0
ft.percent=100.0f*float(ft.made)/float(ft.attempts);//计算公式
else
ft.percent = 0;
}
free_throws & accumulate(free_throws & target,const free_throws & source)//接收两个结构参数,并将第二个结构的成员attempts和made
//添加到第一个结构的相应成员中,只修改了第一个结构,因此第一个参数为引用,第二个参数为const引用
//但是我们发现这是有返回值的,display(accumulate(team,two))就可以解释了,
//首先将结构对象team作为第一个参数传给了accumulate(),这意味着在函数accumulate中,target指向的就是team,函数可以修改team
//再返回指向它的引用,return target是返回语句
//光看这一点并不能知道返回的是引用,但是函数头和原型指出了这一点
//如果返回值类型被声明free_throws而不是free_throws &上述语句将返回target(也就是team)的拷贝。但是返回类型是引用,这意味着返回的是最初传递给accumulate
//接下来将accumulate的返回值作为参数传递给display,这意味着team传递给了display()。display的参数作为引用,这意味着函数display中的ft指向的是team,因此
//将显示team的内容
{//累加函数
target.attempts+=source.attempts;
target.made+=source.made;
set_pc(target);
return target;
}
介绍一下程序
这个程序首先初始化了多个结构对象。如果指定的初始值较少,余下的成员将会被设置为0
在上述代码中我们就需要注意const用法和引用变量作为函数参数和结构体定义的问题了
如果实参与引用参数不匹配,c++将生成一个临时变量。当前,仅当参数为const引用时,则编译器将在下面两种情况中生成临时变量:
1.实参的类型正确但不是左值。
2.实参的类型不正确但是可以转换成别的类型。
3.介绍左值
左值参数是可被引用的数据对象,例如,变量,数组元素,结构成员,引用和解除引用的指针都是左值。非左值包括字面常量(用括号括起来的字符串除外,他们由地址表示)和包含多项的表达式。在c语言中,左值最初指的是可出现在赋值语句左边的实体,但这是引入关键字const之前的情况。现在常规变量和const变量都可以视为左值,因为可以通过地址访问他们。但常规变量属于可修改的左值,而const属于不可修改的变量。
应该尽可能的使用const
将引用变量声明为常量数据的引用的里有有三个:
1.使用const可以避免无意中修改数据的编程错误
2.使用const使函数能够处理const和非const实参,否则将只能接受非const变量数据
3.使用const引用使函数能够正确的生成临时变量
更深入的了解返回应用和传统返回机制的不同
传统返回机制与按值传递函数参数类似:计算关键字return后面的表达式,并将结果返回给调用函数。从概念上说,这个值被复制到一个临时位置,而调用程序将使用这个值
double m=sqrt(16.0);
cout<<sqrt(25.0);
在第一条语句,值4.0被复制到一个临时变量,然后被复制给m。在第二条语句中,值5.0被复制到一个临时位置,然后传递给cout
接下来我们看一行代码
dup=accumulate(team,five);
如果accumulate返回给一个结构,而不是指向结构引用,将把整个结构复制到一个临时变量,再将这个拷贝给dup。但在返回值为引用时,将直接把team复制到dup,效率更高
返回引用的函数实际上是被引用的变量的别名
返回时要注意的一点是,应避免返回函数终止时不再存在的内存单元引用。应避免写下面的代码
const free_throws & clone2(free_throws & ft)
{
free_throws newguy;
newguy = ft;
return newguy;
}
该函数返回的是一个指向临时变量的引用,函数运行完之后它将不复存在。
为了避免这样的问题,最简单的方法就是,返回一个作为参数传递给函数的引用。作为参数的引用将指向调用函数使用的数据,因此返回的引用也将指向这些数据。