注释包含许多关键点以及注意事项
#include <iostream>
using namespace std;
/*
C++中引用可以看做是一个数据的别名,通过别名和原来的名字都能够找到这份数据
引用的定义方式类似于指针,只是用&取代了*
type & name = data;
注:
引用必须在定义的时候初始化,并且要从一而终,不能引用其它数据,这点有点类似于常量(const变量),
而且必须绑定到变量、对象等上去,不能绑定到常量上去。
引用在定义时需添加 & , 使用时候无需加 &, 使用时加&表示取地址(定义变量时&在左边是引用,右边是取地址)
引用作为返回参数的时候,返回的数据不能是局部变量Fun3
*/
void quoteFun(void)
{
int a = 99;
int &r = a;
cout << a << " " << r << endl;
cout << &a << " " << &r << endl;
r = 10;
cout << a << " " << r << endl;
}
void swap1(int a, int b)
{
int temp = a;
a = b;
b = temp;
}
void swap2(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
void swap3(int &r1, int &r2)//形参引用会改变传入的值
{
int temp = r1;
r1 = r2;
r2 = temp;
}
void quoteFun2(void)
{
int num1 = 3, num2 = 5;
swap1(num1, num2);//形参并没有进行替换
cout << num1 << " " << num2 << endl;
num1 = 3, num2 = 5;
swap2(&num1, &num2);//常见的指针的方式
cout << num1 << " " << num2 << endl;
num1 = 3, num2 = 5;
swap3(num1, num2);//用引用的方式实现替换
cout << num1 << " " << num2 << endl;
}
int "eTest(int &r)
{
int m = r + 10;
//return n;
return m;
}
void quoteFun3(void)
{
int num1 = 10;
int num2 = quoteTest(num1);
cout << num1 << " " << num2 << endl;
int &num3 = quoteTest(num1);
int &num4 = quoteTest(num3);
cout << num3 << " " << num4 << endl;
}
int num = 99;
class A
{
public:
A();
private:
int n;
int &r;
};
A::A() :n(0), r(num) {}
void quoteFun4(void)
{
/*
变量是要占用内存的,虽然我们称 r 为变量,但是通过&r获取到的却不是 r 的地址,
而是 a 的地址,这会让我们觉得 r 这个变量不占用独立的内存,它和 a 指代的是同一份内存。
*/
A *a = new A();
cout << sizeof(A) << endl;
cout << hex << showbase << *((int*)a + 1) << endl;
cout << &num << endl;
/*
从运行结果来看
成员变量 r 是占用内存的,如果不占用的话,sizeof(A)的结果应该为 4。
r 存储的内容是0x442000,也即变量 num 的地址。
其实引用只是对指针进行了简单的封装,它的底层依然是通过指针实现的,
引用占用的内存和指针占用的内存长度一样,在 32 位环境下是 4 个字节,
在 64 位环境下是 8 个字节,之所以不能获取引用的地址,是因为编译器进行了内部转换。
*/
}
/*
引用和指针的其它区别
1、引用必须在定义时初始化,并且以后也要从一而终,不能再指向其他数据;
而指针没有这个限制,指针在定义时不必赋值,以后也能指向任意数据。
2、指针可以有多级,但是引用只能有一级,例如,int **p是合法的,
而int &&r是不合法的。如果希望定义一个引用变量来指代另外一个引用变量,那么也只需要加一个&
3、指针和引用的自增(++)自减(--)运算意义不一样。对指针使用 ++ 表示指向下一份数据,
对引用使用 ++ 表示它所指代的数据本身加 1;自减(--)也是类似的道理。
*/
/*
指针只能指向内存,不能指向寄存器和硬盘
例如:表达式的结果、函数的返回值,它们可能放在寄存器也可能放在内存
放在寄存器中用&来获取它们的地址是不对的
int m = 10, n=20;
int *p = &(m + n);
int *p2 = &(n + 100);
bool *p4 = &(m < n);
这些结果都会被放到寄存器中
int fun()
{
int n = 100;
return n;
}
int *p3 = &(fun());//这个临时结果也会存在寄存器中
常量表达式的值虽然在内存中,但是没有办法寻址,所以也不能使用&来获取它的地址,更不能用指针指向它。
引用和指针在本质上是一样的,引用仅仅是对指针进行了简单的封装。故引用也只能对内存进行取址
*/
bool is0dd(int &n)
{
if (n % 2 == 0)
{
return false;
}
else
{
return true;
}
}
void quoteFun5(void)
{
//函数参数是引用类型,只能传递变量,不能传递常量或者表达式。
int a = 100;
is0dd(a);//正确
//is0dd(a+9);//错误
//is0dd(3);//错误
/*
引用不能绑定到临时变量,但是加了const关键字后,可以绑定到临时数据了
常引用绑定到临时数据时,编译器会创建一个新的、无名的变量,然后将引用绑定到该临时变量
将函数修改
bool is0dd(const int &n);
is0dd(a+9);
is0dd(3);
正常运行
注:
给引用添加 const 限定后,不但可以将引用绑定到临时数据,还可以将引用绑定到类型相近的数据,
这使得引用更加灵活和通用,它们背后的机制都是临时变量。
char c = '@';
char &r3 = c; //正确
const int &r4 = c; //正确
将引用类型形参添加const限制理由有三:
使用 const 可以避免无意中修改数据的编程错误;
使用 const 能让函数接收 const 和非 const 类型的实参,否则将只能接收非 const 类型的实参;
使用 const 引用能够让函数正确生成并使用临时变量。
*/
}
int main(void)
{
quoteFun4();
system("pause");
return 0;
}