普通引用和常引用
- 變量名的回顧
變量名實質上是一段連續存儲空間的別名,是一個標號(門牌號)
程序中通過變量來申請並命名內存空間
通過變量的名字可以使用存儲空間
問題:一段連續的內存空間是否只能有一個別名嗎?
- C++引用的概念
引用可以看作一個已定義變量的別名
引用的語法:Type& name = var;
注:普通引用在聲明時必須用其它的變量進行初始化
- 引用意義
1)引用作爲其它變量的別名而存在,因此在 一些場合可以代替指針
2)引用相對於指針來說具有更好的可讀性和實用性
- 引用的本質
引用在C++中的內部實現是一個常指針
Type& name çè Type* const name
C++編譯器在編譯過程中使用常指針作爲引用的內部實現,因此引用所佔用的空間大小與指針相同。
從使用的角度,引用會讓人誤會其只是一個別名,沒有自己的存儲空間。這是C++爲了實用性而做出的細節隱藏
當我們使用引用語法的時,我們不去關心編譯器引用是怎麼做的
當我們分析奇怪的語法現象的時,我們纔去考慮c++編譯器是怎麼做的
#include <stdio.h>
#include <stdlib.h>
int main5_1()
{
// 定義變量 a,a 是一個整形變量,佔4個字節
// a 變量代表這4個字節的內存,a就是這塊內存的名字
int a = 10;
// 定義一個引用變量,b 是 a 的引用
// a 是一塊4字節內存的名字,引用的意思是給這塊內存重新取個名字
// b a代表的那塊內存的別名,b 和 a 代表同一塊內存
// 引用的語法: 在定義變量的時候在變量前加 &
int &b = a;
int c = 40;
// 這是複製操作,將c的之賦給b
// 普通引用在定義必須要初始化,引用是一塊空間的別名,
// 如果空間不存在,引用就沒有意義
b = c;
b = 90;
printf (“a = %d, b = %d, c = %d\n”, a, ,b, c);
return 0;
}
void swap5_1(int* a, int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void swap5_3(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
int main5_2()
{
int a = 10;
int b = 20;
swap (a, b);
// swap (&a, &b);
printf (“a = %d, b = %d\n”, a, b);
return 0;
}
struct A
{
int id;
char name[20];
};
void init (A** p)
{
p = (A)malloc(sizeof(A)/sizeof(char));
}
// 指針引用
void init1 (A* &p)
{
p = (A*)malloc(sizeof(A)/sizeof(char));
p->id = 20;
}
int main5_3()
{
A* pa = NULL;
// init (&pa);
init1 (pa);
printf (“id = %d\n”, pa->id);
return 0;
}
void func (A* pa)
{
printf (“id = %d, name = %s\n”, pa->id, pa->name);
}
void func5_1 (A &a)
{
// 引用是空間的別名,操作結構體的時候用
printf (“id = %d, name = %s\n”, a.id, a.name);
}
int main5_4()
{
A a = {10, “wang”};
// func (&a);
func5_1 (a);
return 0;
}
struct B
{
double &a;
double &b;
};
int main5_5()
{
double a = 10;
double &b = a;
printf (“size = %d\n”, sizeof(b));
// 引用本質是指針,常指針
printf (“B = %d\n”, sizeof(B));
return 0;
}
#include <stdio.h>
void swap5_6(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
// ====>
#if 0
int swap5_6(int * const a, int * const b)
{
int temp = *a;
*a = *b;
*b = temp;
}
#endif
int main5_6()
{
int a = 0;
int &b = a; // 常指針:====> int * const b = &a;
b = 90; // *b = 90;
printf ("&a = %p, &b = %p\n", &a, &b); // &b ==> &(*b)
printf (“a = %d, b = %d\n”, a, b);
return 0;
}
// 函數返回值是引用,不能返回棧上的引用,可以返回靜態變量和全局變量的引用
int &func5_6()
{
static int a;
a++;
printf (“a = %d\n”, a);
return a;
}
int main5_7()
{
for (int i = 0; i < 10; i++)
{
func5_6();
}
// 1、函數返回值是引用,如果用引用去接,接回來的是一個 引用
int &b = func5_6();
b = 100;
func5_6();
// 2、函數返回值是引用,可以用普通變量去接,接回來的是一個 值
int c = func5_6();
printf (“c = %d\n”, c);
c = 200;
func5_6();
// 3、函數返回值是引用,可以作爲左值來使用
func5_6() = 200;
printf (“b = %d\n”, b);
func5_6();
return 0;
}
int add(int &a, int &b)
{
return a + b;
}
int main6_1()
{
int a = 10;
int b = 20;
printf (“a + b = %d\n”, add(a, b));
// printf (“a + b = %d\n”, add(10, b));
// int &c = 10; // int * const c = &10;
return 0;
}
int add2(const int &a, const int &b)
{
return a + b;
}
int main6_3()
{
printf (“a + b = %d\n”, add2(10,20));
return 0;
}
int main6_2()
{
// 常量 放在常量表中
const int a = 10;
int c = 10;
// 普通引用
int &b = c;
// 常引用,意思不能通過引用改變被引用的值
const int &d = c; // const int * const d = &c;
// 常引用的初始化有2中方式
// 1、引用普通變量,不能改變變量的值
{
int a1 = 100;
const int &ra = a1;
}
// 2、使用常量去初始化常引用
{
// 當使用常量對常引用進行初始化的時候,編譯器會爲這個常量分配一塊空間
// 將這個常量的值複製到這個空間裏
// 然後讓這個常引用作爲這個空間的別名
const int &ra = 10; // const int * const ra = &10;
// ra = 90;
int *p = (int *)&ra;
*p = 200;
printf (“ra = %d\n”, ra);
}
return 0;
}