C++ const与引用
const
被const修饰的变量不可被修改,在定义的时候,就必须赋值。
如果修改的类、结构体(的指针),其成员已不可以被修改。
struct Date
{
int year;
int month;
int day;
};
int main()
{
const int a = 1;
a = 2; // 错误
const Date d = { 2021, 7, 3 };
Date d1 = { 2021, 8, 3 };
d = d1; // 错误
d.year = 2015; // 错误
Date *p = &d1; // 如果改成 Date *p = &d1,下面3行操作全部都会报错
p->year = 2015; // d1.year: 2015;
(*p).month = 5; // d1.month: 5;
*p = d; // p->year: 2021
return 0;
}
以下5个指针分别声明的含义:
int main()
{
int a = 10;
int b = 20;
// *p1是常量,p1不是常量,所以,p1是可以修改的,而*p1是不可以被修改的
const int *p1 = &a;
*p1 = 20; // error
p1 = &b; // ok
int const *p2 = &a; // 和p1一样。
// p3是常量,*p3不是常量,所以,*p3是可以修改的,而p3是不可以被修改的
int * const p3 = &a;
*p3 = 20; // ok
p3 = &b; // error
// p4是常量,*p4也是常量,所以,p4和*p4都不可以被更改
const int * const p4 = &a;
*p4 = 20; // error
p4 = &b; // error
int const * const p5 = &a; // 和p4一样
return 0;
}
const修饰的是右边的内容
引用
在C语言里,可以使用指针间接访问和修改某个变量的值。
int main()
{
int a = 10;
int *p = &a;
*p = 20; // a = 20
return 0;
}
C++中,使用引用可以起到跟指针类似的功能。
struct Date
{
int year;
int month;
int day;
};
int main()
{
int a = 10;
int &ref = a;
ref = 20; // a = 20;
// 结构体的引用
Date d = { 2021, 7, 3 };
Date &d_ref = d;
d_ref.month = 5;
// 指针的引用
int *p = &a;
int *&p_ref = p;
*p_ref = 20;
// 数组的引用
int array[] = { 1, 2, 3 };
// int (&array_ref)[3] = array; 下面的也可以
int * const &array_ref = array;
array_ref[0] = 10;
return 0;
}
注意
- 引用相当于是变量名的别名(基本数据类型、枚举、结构体、类、指针、数组等,都可以有引用)。
- 对引用做计算,就相当于对引用指向的变量做计算。
- 在定义的时候必须初始化,一旦指向了某个变量,就不可以修改引用的指向。可以修改引用里的值。
- 不存在引用的引用、指向引用的指针、引用数组。
本质
- 引用就是指针,只是编译器削弱了它的功能,它就是弱化了的指针。
- 一个引用占用一个指针的大小。
使用sizeof运算符可以简单证明一下。
// 系统是x64的,所以,一个指针占用8个字节
struct Int
{
int a;
};
struct P
{
int *a;
};
struct Ref
{
int &a;
};
int main()
{
printf("%d\t%d\t%d", sizeof(Int), sizeof(P), sizeof(Ref));
return 0;
}

const引用
引用可以被const修饰,这样就无法通过引用修改数据了,可以称为常引用。
const必须写在&符号的左边,才能算是常引用。例如:const int &ref = 30;
int main()
{
int a = 10;
const int &ref1 = a;
ref1 = 30; // error
int & const ref2 = a; // 不能修改ref2的指向,本来就不可以修改,没有意义。
ref2 = 1; // ok
return 0;
}
特点
-
可以指向临时数据(常量、表达式、函数返回值等)。
-
可以指向不同的类型的数据。
-
可以作为函数的形参时:(此规则同样适用与
const指针)- 可以接受
const和非const实参(非const引用,只能接受非const实参)。 - 可以跟非
const引用构成重载。
- 可以接受
-
当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量。
int sum(const int &a, const int &b) { return a + b; } int main() { int a = 1, b = 2; // int &ref = 30; // error const int &ref = 30; // ok // int &ref = a + b; // error const int &ref2 = a + b; // ok // double &ref = a; // error const double &ref = a; sum(10, 30); return 0; }
指针/引用的本质
int a = 1;
int *p = &age;
*p = 2;
上面三句代码的汇编代码如下
mov dword ptr[ebp-0Ch], 1; int a = 1; ebp-0Ch就是a的地址
lea eax, [ebp-0Ch]; 将ebp-0Ch赋值给eax,即eax == ebp-0Ch。这时候,eax存放的是a的地址
mov dword ptr [ebp-18h], eax; int *p = &a; eax存放的是a的地址,所以,指针变量p里的值,就是a的地址。ebp-18h是指针变量p的地址
mov eax, dword ptr [ebp-18h]; 取ebp-18h(指针p)存储的值(就是a的地址),赋值给eax
mov [eax], 2; *p = 2; 将eax存放的地址(a的地址)的值修改为2。