首页 > 代码库 > C++ 引用(1)

C++ 引用(1)

一、什么是引用?

# include<iostream>
using namespace std;
int main()
{
	int num;
	int &mum=num;
	//这就好像李四有个外号叫李大嘴,大家称呼李四指的是李四这个人,称呼李大嘴也是指的是李四这个人,李四和李大嘴都是一个人,只是名字不同而已。
    //对num的操作也就是对mum的操作,&mum不是取地址符,而是引用符号。他们的符号相同,但是功能不同。应用就是别名。
	num=999;
	cout<<"num的值为:"<<num<<endl;
	cout<<"mum的值为:"<<mum<<endl;
	num=100;
    cout<<"num的值为:"<<num<<endl;
	cout<<"mum的值为:"<<mum<<endl;
	return 0;
}

运行结果:

技术分享

二、引用的地址

# include<iostream>
using namespace std;
int main()
{
	int a;
	int &ra=a;
	cout<<"a的地址为:"<<&a<<endl;
	cout<<"ra的地址为:"<<&ra<<endl;
	return 0;
}

运行结果:

技术分享

注释:因此对ra的操作就是对a的操作。因为他们的地址是一样的。

三、引用就是别名常量

# include<iostream>
using namespace std;
int main()
{
	int a;
	int &ra=a;
	a=555;
	cout<<"a的地址为:"<<&a<<endl;
	cout<<"ra的地址为:"<<&ra<<endl;
    cout<<"a的值为:"<<a<<endl;
	cout<<"ra的值为:"<<ra<<endl;
	int b=999;
	ra=b;
	cout<<"a的地址为:"<<&a<<endl;
	cout<<"ra的地址为:"<<&ra<<endl;
	cout<<"b的地址为:"<<&b<<endl;
	cout<<"a的值为:"<<a<<endl;
	cout<<"ra的值为:"<<ra<<endl;
	cout<<"b的值为:"<<b<<endl;
	//把b的值付给ra,那么a和ra的值都给改变了,但是地址并没有变化。
	ra=100;
    cout<<"a的值为:"<<a<<endl;
	cout<<"ra的值为:"<<ra<<endl;
	cout<<"b的值为:"<<b<<endl;
	//a和ra的值又便换来了。
	//在这个实例中,我们将ra定义为a的值,ra只是属于a,但是他不会因为b而变成b的别名,但是他会因为b的赋值,把变量a也变成b的值。
	//ra是a的别名,我们不能改变,但是我们却可以改变ra的值,这样还会导致a的值得改变。
	return 0;
}
运行结果:

技术分享

四、引用对象

# include<iostream>
using namespace std;
class Human
{
public:
	int get(){return i;}
	void set(int x){i=x;}
private:
	int i;
};
int main()
{
	Human Mike;
	Human &rMike=Mike;
	//对象的别名
	//Human &rHuman=Human;
	//以上是错误的,我们不能定义类的引用。Human是一个类,他们有具体的内存地址,我们不能定义一个类的引用。
	rMike.set(123);
	cout<<rMike.get()<<endl;
	//以上看来,rMike是和MIke一样的。
	return 0;
}

运行结果:

技术分享

五、空引用

我们知道指针进行删除操作后,需要将它们赋为空,引用却不需要这么做,这是因为引用是原来对象的别名,假如该对象存放在栈中,那么在对象超出作用域时别名会和对象一起消失。假如该对象存放在堆中,由于堆中内存空间必须使用指针来访问,因此用不着别名,即使再定义一个该指针的别名,那么将指针删除并赋空之后,该指针的别名中的地址也相应的赋空了。

六、按值传递


# include<iostream>
using namespace std;
void swap(int a,int b)
{
	int c;
	cout<<"swap函数中,交换前,a:"<<a<<"\t"<<"b:"<<b<<endl;
	c=a;
	a=b;
	b=c;
	cout<<"swap函数中,交换后,a:"<<a<<"\t"<<"b:"<<b<<endl;
}
int main()
{
	int a=3,b=4;
	cout<<"主程序中,交换前,a:"<<a<<"\t"<<"b:"<<b<<endl;
	swap(a,b);
    cout<<"主程序中,交换后,a:"<<a<<"\t"<<"b:"<<b<<endl;
	return 0;
}

运行结果:

技术分享

注释:

以上这个问题很简单,swap函数交换的是main函数中a和b的副本的值;也就是说在main函数中定义的a和b的备份的值;swap函数交换的是main函数中的a和b的副本,而不是a和b本身;这是因为当我们直接将a和b传递给swap函数时,这样的传递是按值传递;假如将a和b按值传递给swap函数,那么编译器会自动在栈中创建a和b的拷贝,然后将a和b的拷贝传递给swap函数。在swap函数中对a和b的拷贝进行交换。因此我们看到的输出语句,a和b确实进行了交换,只不过交换的是a和b的副本。由于交换的是a和b的副本,并不是a和b本身,所以在swap函数结束后,输出的值显示main函数中的a和b并没有改变。

七、按址传递

# include<iostream>
using namespace std;
void swap(int *a,int *b)
{
	int c;
	//以下是交换主函数中a和b的值,所以要带*。
	cout<<"swap函数中,交换前,a:"<<*a<<"\t"<<"b:"<<*b<<endl;
	c=*a;
	*a=*b;
	*b=c;
	cout<<"swap函数中,交换后,a:"<<*a<<"\t"<<"b:"<<*b<<endl;
}
int main()
{
	int a=3,b=4;
	cout<<"主程序中,交换前,a:"<<a<<"\t"<<"b:"<<b<<endl;
	swap(&a,&b);
	//传递的是a和b的地址。
    cout<<"主程序中,交换后,a:"<<a<<"\t"<<"b:"<<b<<endl;
	return 0;
}
//通过地址的传递,我们能直接访问到a和b的地址,因此修改的也是a和b的值,而不是他们的副本。

运行结果:

技术分享

八、按别名传递

# include<iostream>
using namespace std;
void swap(int &a,int &b)
//这里的a和b不是主函数中的a和b,这里的a和b是主函数a和b的别名,传递的是主函数中a和b中的别名,这个比址传递还要简单。
//通过a和b的别名可以交换a和b的值。
{
	int c;
	cout<<"swap函数中,交换前,a:"<<a<<"\t"<<"b:"<<b<<endl;
	c=a;
	a=b;
	b=c;
	cout<<"swap函数中,交换后,a:"<<a<<"\t"<<"b:"<<b<<endl;
}
int main()
{
	int a=3,b=4;
	cout<<"主程序中,交换前,a:"<<a<<"\t"<<"b:"<<b<<endl;
	swap(a,b);
    cout<<"主程序中,交换后,a:"<<a<<"\t"<<"b:"<<b<<endl;
	return 0;
}

运行结果:

技术分享

九、利用指针返回多值

# include<iostream>
using namespace std;
int func(int a,int *b,int *c);
int main()
{
	int a=1,b=2,c=3;
	cout<<"主程序,调用func函数前...\n";
	cout<<"a:"<<a<<endl<<"b:"<<b<<endl<<"c:"<<c<<endl;
	func(a,&b,&c);
	cout<<"主程序,调用func函数后...\n";
	cout<<"a:"<<a<<endl<<"b:"<<b<<endl<<"c:"<<c<<endl;
	//a是值传递,b和c是地址传递
	return 0;
}
int func(int a,int *b,int *c)
{
	cout<<"func函数中,计算前...\n";
	cout<<"a:"<<a<<endl<<"b:"<<*b<<endl<<"c:"<<*c<<endl;
	a=a+1;
	*b=(*b)*(*b);
	//用过b的地址传递,把b的值平方再付给b
	*c=(*c)*(*c)*(*c);
	cout<<"a:"<<a<<endl<<"b:"<<*b<<endl<<"c:"<<*c<<endl;
	return a;
}

运行结果:

技术分享

虽然是返回了a值,但是我们可以到是返回了3个值,因为b和c的值也改变了。

我们可以把a看作是返回的判断值,b和c看做运算的返回值。

用该方法我们可以实现汇报执行程序时的非法操作信息。

# include<iostream>
using namespace std;
int func(int a,int *b,int *c);
int main()
{
	int a,b,c;
	int check;
	cout<<"请您输入要进行运算的数字,";
	cout<<"您输入的数字将作为园的半径和正方形的边长:";
	cin>>a;
	check=func(a,&b,&c);
	if(check)
	{
		cout<<"输入的数字超过计算范围!\n";
	}
	else
	{
		cout<<"圆的面积为:"<<b<<endl;
		cout<<"正方形的面积为:"<<c<<endl;
	}
	return 0;
}
int func(int a,int *b,int *c)
{
    if(a>20000)
	{
		a=1;
	}
	else
	{
		*b=a*a*3.14;
		*c=a*a;
		a=0;
	}
	return a;
}

运行结果:

技术分享

但是我们要注意的是:这两个值不是通过返回机制来得到实现的,而是通过改变函数指针参量*b和*c所指向的内存区域中的值来实现的。

十、利用引用来返回多值

以上程序用引用更为方便

# include<iostream>
using namespace std;
int func(int a,int &b,int &c);
int main()
{
	int a,b,c;
	int check;
	cout<<"请您输入要进行运算的数字,";
	cout<<"您输入的数字将作为园的半径和正方形的边长:";
	cin>>a;
	check=func(a,b,c);
	if(check)
	{
		cout<<"输入的数字超过计算范围!\n";
	}
	else
	{
		cout<<"圆的面积为:"<<b<<endl;
		cout<<"正方形的面积为:"<<c<<endl;
	}
	return 0;
}
int func(int a,int &b,int &c)
{
    if(a>20000)
	{
		a=1;
	}
	else
	{
		b=a*a*3.14;
		c=a*a;
		a=0;
	}
	return a;
}

运行结果:

技术分享

由此看出 ,引用更为方便!

C++ 引用(1)