关于引用方面的思维导图
注意点1:有关引用所指向空间的问题
int main()
{
int a = 10;
int& b = a;//引用就是取别名,b叫做a的引用,a的别名---就是个标签
int& c = b;
printf("%pn", &a);//0023FC70
printf("%pn", &b);//0023FC70,地址都是一样的
printf("%pn", &c);//0023FC70
int x = 1, y = 2;
Swap(x, y);//引用就不需要取地址了
a += 1;
c += 1;
printf("%dn", a);//a好像只加了1,但是确实12。
printf("%dn", c);//c也是12哎
return 0;
}
a,b,c使用常量10所在的空间,a+=1,c+=1,由于使用同一块空间,因此要特别注意,改变a也会改变c
2:有关引用的特性
int& b=10; int e=20; b=e;//把e的值赋值给b //然而&b(取地址),发现地址不变,说明已经定义了的b,不能再引用其他的。特别重要的应用---相较于c语言
typedef struct ListNode
{
int val;
struct ListNode* next;
}LTNode,*PLTNode;
//*PLTNode,声明了一个指向ListNode结构体的指针
void LTPushBack_C(LTNode** pphead, int x)
{
//c语言必须要用二级指针,且外面传入必须取地址
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (*pphead == NULL)
{
*pphead = newnode;
}
}
void LTPushBack_CPP(LTNode*& phead, int x)
{
//外面传入一个一级指针,用phead接受这个一级指针,再引用
//而改变phead,就可以改变plist,而plist指向LTNode的空间,就可以修改其对应的值
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (phead == NULL)
{
phead = newnode;
}
}
int main()
{
LTNode* plist = NULL;
//LTPushBack_C(&plist, 1);
LTPushBack_CPP(plist, 1);
return 0;
}
常引用
引入一个概念:读写的权限,只读相对与读写是权限的缩小,读写相对于只读是权限的放大
引用的原则是:权限只能缩小或者不变,不能放大---这是一切问题的理论依据
//引用变量,权限只能缩小或者不变,不能放大
//const int x = 1;//这里的x是只读的
int& y=x;//y是读写的,属于是x相对于y权限的放大
//const int& y = x;//对y加个const去除写权力就可以了
//int a = 2;
//2的值复制给a,a改变并不会改变a的值
//如果int &a=10;就不行了---因为引用a,会直接修改10,这是不被允许的。
//const int& b = a;//缩小权限---只能读
//const int& c = 20;//常量是一个只读的,因为你一个20不能被自己定义,不可以被修改,因此对常量取别名需要加const来修饰
那么就有
void fun(int &x)
{
}
int main()
{
int a=10;
fun(a);//这样就可以
fun(10);//这样就不行了,
return 0;
}
隐式类型转换的例子
//double d = 2.2; //int f = d;//隐式类型转换---创建临时变量---临时变量具有常性---这样,常性就互通了. //const int& e = d;//也就是说,临时变量是个const,到非const就是个权限的放大
前面已经说过,引用的原则是:权限只能缩小或者不变,不能放大---这是一切问题的理论依据
这里的d发生截断的时候会创建一个临时变量,而这个临时变量又是个常变量,因此在引用的时候需要加个const,防止权限进行放大
使用场景1:做参数
//void fun(int &x)
//{
//}
//如果像传fun(10)就必须const int &x
void fun(const int &x)
{
传入进来的a,x作为它的别名,可以修改a的值
}
int main()
{
int a=10;
fun(a);//这样就可以
fun(10);//这样就不行了,
return 0;
}
2:做返回值
传值返回:创建临时变量,临时变量具有常性
int Count()//产生int tmp的临时变量,
{
int n = 0;
n++;
// ...
return n;
}
传引用返回
int& Count()//产生int& tmp的别名,int& ret=Count();接受
{
int n = 0;
n++;
// ...
return n;
}
但是!!!!!
传引用返回是否有点问题?
n已经被销毁了,但是你还要访问那块空间,非法访问了。---像野指针的访问
不安全样例
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);//调用完之后栈帧被销毁
Add(3, 4);//然后,再次调用这个函数,这个函数会把原来的那块栈帧给覆盖,ret还是指向那块内存
即,恰巧ret指向了Add(3,4)栈帧创建的位置
cout << "Add(1, 2) is :"<< ret <
修正
传引用返回
int& Count()//产生int& tmp的别名,int& ret=Count();接受
{
static int n = 0;
n++;
// ...
return n;
}
//这样,传引用返回,static出函数作用域就不会被销毁了。
总结!!!
注意:如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已
经还给系统了,则必须使用传值返回。
指针与引用区别
内联函数---提高调用效率
以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,
内联函数提升程序运行的效率
//#define add(int x,int y) return ((x)+(y))//err
#define add(x,y) ((x)+(y))
int Add(int x, int y)
{
return x + y;
}
int main()
{
Add(10, 20);
Add(10, 20);
Add(10, 20);
Add(10, 20);
Add(10, 20);
return 0;
}
inline在符号表里面没有地址,因此链接找不到



