引用
基本概念
定义︰引用是为已存在的变量取了一个别名,引用和引用的变量共用同一块内存空间。
引用就是某一变量(目标〉的一个别名,也就是说,它是某个己存在变最的另一个名字。对引用的操作与对变量名直接操作完全一样。
引用的初始化
类型&引用变量名=目标变量名;
上述格式中,“&”并不是取地址操作符,而是起标识作用,标识所定义的标识符是一个引用。引用声明完成以后相当于口标变量有两个名称
#include<iostream>
using namespace std;
int main() {
int b = 1;
int& a = b;
int c = 3;
a = c;
#int &a = c; 错误 ,引用一旦初始化,其值就不能再更改,即不能再做别的变量的引用
cout << a << endl;
return 0;
}
#结果为3
引用的特点
●引用实体和引用类型必须为同种类型(引用在初始化时只能绑定左值不能绑定常量值)
●引用在定义时必须初始化并且不能被初始化为NULL,不能更改引用关系-》引用的底层使用指针常量来实现的 int * const p如int &b;是错误的。
●引用一旦初始化,其值就不能再更改,即不能再做别的变量的引用(不可以改变引用关系)
●数组不能定义引用,因为数组是一组数据,无法定义其别名。
2.函数参数(避免拷贝构造节约时间成本空间成本),函数返回值避免拷贝构造
const与引用
被const修饰的变量其引用必须也要被const修饰。
#include<iostream>
using namespace std;
int main(){
const int a = 1;
int& b = a; //报错,应该为const int &b=a;
const int& c=a; //表示不可以通过c修改a
return 0;
}
参数与引用
引用作为函数参数时的原因:
1.在函数内部会对此参数进行修改
2.提高函数调用和运行效率
函数调用时,值的传递机制是通过“形参=实参"来对形参赋值达到传值目的,产生了一个(实参的副本)。而引用不用经过值的传递机制,已经有了实参值的信息。所以没有了传值和生成副本的时间和空间消耗。当程序对效率要求比较高时,这是非常必要的。
#include<iostream>
using namespace std;
void swap(int& a,int& b){
int c = a;
a= b;
b = c;
}
int mian(){
int a = 1,b = 2;
swap(a,b);//在函数中可以修改上行的a和b
cout<<a<<" "<<b<<endl;
return 0;
}
返回值与引用:
返回值为引用的好处:在内存中不产生被返回值的副本
#include<iostream>
using namespace std;
int& fun(int a)
{
a+=2;
return a ;
}
int main (){
int a = 3 ;
int b = fun (a);
cout <<a << endl;
return 0;
}
引用和指针的区别
1.引用在定义时必须被初始化并且不能被初始化为NULL,指针没有要求
2.引用不能改变引用关系,指针随意
3.有多级指针没有多级引用
4.(引用++)和(指针++)表达的含义不同。指针自增是指针上的计算,引用自增单纯加1
5.指针用sizeof计算大小结果不同,指针在32位(x86)内存下是四字节,在64位内存下是8字节,引用结果为类型大小
6.指针是一个实体,需要分配内存空间;引用只是变量的别名,不需要分配内存空间
函数参数默认值
定义:在函数声明或者函数定义的时候直接给形参赋值,这样在函数调用的时候可以不需要再给形参传值,会使用它的默认值。
**注意:**参数默认值必须从右向左依次赋值。
#include<iostream>
using namespace std;
void fun0(int t ,int a = 2, int b = 3)//可以只传前两个值,此时a不在等于默认值,会输出实参的值a=1;
cout<< a <<b;
void fun1(int t = 2, int a , int b = 3)//报错,默认实参不在形参列表的结尾
(
cout << a <<b;
int main (){
fun0 (1,1);
return 0;
}
左值:能取到地址的 ( 有名字的都是左值) 变量:a,b,…
右值:不能取到地址 (没有名字的是右值) 常量:12 ,"asd” , 函数的返回值
左值引用:左值引用只能引用左值int b = 2 ; int &a = b;4.
右值引用:只能引用右值int &&a= 12;
万能引用:即可以引用左值也可以引用右值,拷贝构造函数使用的是万能引用既可以接受左值也可以接受右值
const int& a = b;
const int& c = 68;
int a1 = 68;
int &b1 = a1;
#int &b2 = 76;错,
int &&c1 = 76;
#int &&c1 = a1;错,
int a = 66;
const int& b = a;
const int& c = 12;
*/
/*
赋值:给一个已经存在的对象一个值int a ; a= 1;;
初始化:int a= 1;
*/
引用应用
C++增加引用的类型,主要的应用就是把它作为函数的参数,以扩充函数传递数据的功能,引用作函数参数时是区别于值传递与址传递的引用传递。
利用引用传递可以克服值传递与址传递中容易出现错误且程序的可读性差的缺点。直接操作变量,简单高效可读性又好。
引用 vs 指针主要的不同:
引用在定义时必须被初始化并且不能被初始化为NULL,指针没有要求,存在空指针
一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。(引用不能改变引用关系,指针随意)
有多级指针没有多级引用
引用++和指针++表达的含义不同。指针自增是指针上的计算,引用自增单纯加1
指针用sizeof计算大小结果不同,指针在32位内存下是四字节,在64位内存下是8字节,引用结果为类型大小
指针是一个实体,需要分配内存空间;引用只是变量的别名,不需要分配内存空间
引用与指针的区别
const
一句话让你彻底掌握const
const:首先作用于左边,如果左边没东西,就作用于右边
const int
int const
const int* const
int* const:指针本身不可改变,常量指针 //顶层
const修饰指针p表示指针不可修改,即一旦得到了某个变量的地址,不能再指向其它变量:
int i = 10;
int * const p = &i;
p++;//p指针指向下一个元素,错误
虽然指针不可修改,但是可以修改指针所指向的变量的值:
const int*:指针指向的内容不可改变 //底层
顶层 底层
顶层:对象本身是const
类中,const算入函数签名signature
const :
在类中常函数和非常函数也是重载关系:
不能修改成员变量,如果想修改成员变量需要在成员变量前加mutable 。常函数为什么不能修改成员变量:
常对象不能被修改,常对象只能调用常函数-》常函数不能修改成员变量,常函数中*this会被const修饰。
int *p;
int * const p;修饰 指针变量p不能被修改
const int *p;或者int const *p;修饰的是 *p不能被修改
const 的本质是修饰变量不能被修改,被const 修饰的是变量不是常量,在c语言中被const修饰的变量可以通过指针被修改
非常对象可以调用常函数,如果常函数和非常函数重载优先调用非常函数
include
std namespace std;
void fun(int a){}
int main(){
int* a[3];//指针数组存放指针的数组
//数组指针 数组的指针a1+=1;移动的内存是3* 4=12
//*和 al被括起来表示的是,a1是指针变量指向的是大小为12个字节的int类型的数组.
int (*a1)[3];
//指针函数指的是函数的返回值为指针类型
//函数指针是指向函数的指针
void(*fun1)(int) = fun;
//*和 fun1被括号括起来表示fun1是一个指针变量指向的是返回值为void参数为int 类型的函数
}