C++学习:引用

1.引用的基础:为某一变量的同一地址取一个别名。

#include<iostream>
using namespace std;
int main()
{
	int a = 0;
	int &b = a;
	printf("b:%d\n", b);

	b = 100;
	printf("a:%d\n", a);

	a = 200;
	printf("b:%d\n", b);
	//a就是b,b就是a;

	return 0;
}

2.引用是C++ 的概念范畴:
  当出现引用的语法时,请不要再用C语言的语法思想来思考;

3.引用作为函数参数:

e.g.要实现a和b两个数值的交换:

若采用以下代码:

#include<stdio.h>
void myswamp(int a,int b) {
	int c;
	c = a;
	a = b;
	b = c;
}
int main()
{
	int x,y;
	x = 10;
	y = 20;

	myswamp(x, y);

	printf("x:%d,\ny:%d\n", x, y);

	return 0;
}

则无法实现交换功能;

在C语言中,以指针作为函数参数时,可以实现交换:

#include<stdio.h>
int myswamp(int *a, int *b) {
	int c;
	c =*a;
	*a = *b;
	*b = c;
	return 0;
}
int main()
{
	int x, y;
	x = 10;
	y = 20;

	myswamp(&x, &y);

	printf("x:%d,\ny:%d\n", x, y);

	return 0;
}

上述代码则可以实现数值交换。

也可以在C++中以引用作为函数参数实现上述功能:

#include<iostream>
using namespace std;
void myswamp(int &a, int &b) {
	int c;
	c = a;
	a = b;
	b = c;
}
int main()
{
	int x, y;
	x = 10;
	y = 20;

	myswamp(x, y);//把实参x赋给形参a,y和b也一样;相当于a和b分别是x和y的引用

	printf("x:%d,\ny:%d\n", x, y);

	return 0;
}

//***********************************************************************************************************************************************

复杂数据类型做函数参数引用:

#include<iostream>
using namespace std;
struct Teacher {
	char name[64];
	int age;
};
void printfT1(Teacher *pT) {

	cout << pT->age << endl;
}
void printfT2(Teacher &pT) {

	cout << pT.age << endl;
}
void printfT3(Teacher pT) {

	cout << pT.age << endl;
}
//对比三个函数的不同;

int main()
{
	Teacher T1;
	T1.age = 35;

	printfT1(&T1);

	printfT2(T1);//pT是T1的别名;

	printfT3(T1);//pT是形参,T1拷贝一份给pT;---->pT=T1;

	return 0;
}

思考引用的意义:

引用的意义:
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针来说具有更好的可读性和实用性

//*****************************************************************************************************************************************************

引用本质的思考:

C++编译器在背后做了哪些工作??

#include<iostream>
using namespace std;
int main()
{
	const int c1 = 10;

	int a = 0;
	int &b = a;//引用和const一样,都需要在定义的时候初始化,这一点引用和const很像;

	printf("&a:%d\n", &a);
	printf("&b:%d\n", &b);//引用变量的地址和原变量的地址一样,引用就是为这个内存地址起了个别名;
	return 0;
}

思考2:

引用在定义时是否占据了内存空间??

#include<iostream>
using namespace std;
struct Teacher {
	char name[64];
	int age;

	int &a;		//很像指针所占的内存空间的大小----4个字节----指针就是4个字节,和类型没有关系;
	int &b;
};

int main()
{
	printf("sizeof(Teacher):%d", sizeof(Teacher));//76=64+4+4+4;---所以占空间

	return 0;
}

综上所述:

可以知道引用的本质就是:

1)引用在C++中的内部实现是一个常指针
Type& name Type* const name
2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏

有如下:

void modifyA(int &a) {

	a = 100;

}
void modifyA(int *const a) {

	*a = 10; //*实参的地址去间接的修改实参的值;

}

调用这个函数时编译器的实际操作;
如果形参是指针,则需要程序员手动的取实参的地址;
modifyA(*a);

所以:

#include<iostream>
using namespace std;
int main()
{

	int a = 10;

	modifyA(a);//在执行这个函数操作时,程序员不需要再手动取地址;

	return 0;
}

联想间接赋值:
/*
请仔细对比间接赋值成立的三个条件
1定义两个变量 (一个实参一个形参)
2建立关联 实参取地址传给形参
3*p形参去间接的修改实参的值
请问:引用赋值的使用场景,是这三个条件哪几个条件的组合?
*/

#include<iostream>
using namespace std;
void modifyA0(int *p) {

	*p = 200;//3.(第三个条件)
}
int main()
{
	int a = 10;
	int *p = NULL;	//间接赋值成立的三个条件:1.定义两个变量。

	p = &a;

	modifyA0(&a);//2.联立关联。

	return 0;
}

回答:
引用结论 
1)引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一
//当实参传给形参引用的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)

引用的使用注意::::
2)当我们使用引用语法的时,我们不去关心编译器引用是怎么做的
当我们分析奇怪的语法现象的时,我们才去考虑c++编译器是怎么做的

/./****************************************************************************************************************************************************

引用的难点:
//当函数的返回值是引用时:

#include<iostream>
using namespace std;
int getAA1() {
	int a;
	a = 10;
	return a;
}
//返回引用;
//返回的是a的本身
int& getAA2() {
	int a;
	a = 10;
	return a;//a 是局部变量
}
//返回指针;
int* getAA3() {
	int a = 10; 
	return &a;
}
int main()
{
	int a1 = getAA1();

	int a2 = getAA2();

	int &a3 = getAA2();//用两个方法接受引用;----存在bug

	printf("a1:%d,a2:%d,a3:%d\n", a1, a2, a3);

	return 0;
}

//当函数作为左值时:

#include<iostream>
using namespace std;
//g1是返回变量的值,是一个数
int g1() {
	static int a = 10;
	a++;
	return a;
}
//返回变量本身,返回变量的内存空间
int& g2() {
	static int a = 10;
	a++;
	printf("a=%d", a);
	return a;
}
int main()
{
	//g1() = 100;     //g1()--->相当于是数字11,数字11不能当左值;
	g2() = 100;    //相当于--->a=100;----->函数返回值当左值
	g2();

	return 0;
}
//主要看变量的内存空间时全局变量;

有结论:

/*
C++引用使用时的难点:
1.当函数返回值为引用时
        若返回栈变量(局部变量)
        不能成为其它引用的初始值
        不能作为左值使用
2.若返回静态变量或全局变量
        可以成为其他引用的初始值
        即可作为右值使用,也可作为左值使用
C++链式编程中,经常用到引用,运算符重载专题
*/

//****************************************************************************************************************************************************

//指针的引用:

1.)C语言中一级指针作为形参:

#include<stdio.h>
struct Teacher {
	char name[64];
	int age;
};
//一级指针作为函数形参时的代码
void getTeacher(Teacher *p) {//函数int的意思:在被调用函数里面,获取内存资源;---->二级指针
	p->age = 33; 
}
int main()
{
	Teacher T1;
	getTeacher(&T1);
	cout <<"age is: "<< T1.age << endl;

	return 0;
}

2.C语言中二级指针作为形参:

#include<stdio.h>
int getTeacher(Teacher **p) {
	Teacher *temp = NULL;//中间变量,传递值;
	if (p == NULL) {
		return -1;//返回值在这里
	}
	temp = (Teacher *)malloc(sizeof(Teacher));
	if (temp == NULL) {
		return -2;//返回值在这里
	}
	temp->age = 33;
	*p = temp;//p是实参的地址,*是实参的地址,就是间接的修改实参的值
}
int main()
{
	Teacher *pT1 = NULL;	//这里是结构体指针,所以操作函数形参要用二级指针;
	getTeacher(&pT1);
	cout << "age : " << pT1 ->age<< endl;
	return 0;
}

3.C++中指针的引用:

#include<iostream>
using namespace std;
int getTeacher2(Teacher* &myp) {//是个引用
	myp = (Teacher*)malloc(sizeof(Teacher));//给myp赋值,相当于给main中的pt1赋值;
	if (myp == NULL) {
		return -1;
	}
	myp->age = 36;
}
void FreeTeacher(Teacher *pt1) {
	if (pt1 == NULL)
		return;
	free(pt1);
}
int main()
{
	Teacher *pt1 = NULL;
	getTeacher2(pt1);
	cout << "age is :" << pt1->age << endl;
	FreeTeacher(pt1);//释放指针指向的内部空间;
	return 0;
}

//*****************************************************************************************************************************************************

//常引用:

#include<iostream>
using namespace std;
int main() 
{
	//普通引用:
	int a = 10;
	int &b = a;

	//常引用:
	int x = 20;
	const int &y = x;//常引用---作用是让比变量引用只读属性---不能通过y去修改x;

	//常引用的初始化:
	//1.用变量 初始化 常引用:
	{
		int x1 = 30;
		const int &y1 = x1;	//用x1变量取初始化常引用;
	}
	//2.用字面量 初始化 常引用:
	{
		const int a = 10;	//C++编译器把a放在符号表中
		//int &m = 41;	//普通引用引用一个字面量--请问字面量有没有内存地址?----没有!
	    //引用:就是给内存取多个别名

		const int &m = 43;//加上const之后,就可以引用字面量;
		//C++编译器会多给m分配一个内存空间,但是43还是没有内存地址。
	}


	return 0;
}

//案例:

//常引用的案例:
struct Teacher {
	char name[64];
	int age;
};

int printTeacher(const Teacher &myp) {
	//常引用 让实参变量 拥有只读属性
	//myp.age = 36;
	printf("myp.age:%d \n", myp.age);
}

结论:
/*
    const引用的结论:
    1.const& 相当于 const int* const;
    2.普通引用 相当于 int* const;
    3.当使用常量(字面量)对const引用进行初始化时,C++编译器会为常量分配空间,并将引用名作为这段空间的别名;
    4.使用字面量对const引用的初始化,将生成一个只读变量;
*/

猜你喜欢

转载自blog.csdn.net/xuchen1230/article/details/81213524