const引用 常量指针 指向常量的指针
- const对象一旦创建,其值将不可更改,所以const变量必须初始化。
- 只要不改变const的值,const变量就和其他变量一样
1.const对象在多个文件中:
- 默认情况下,
被const修饰的对象仅在文件内中有效
。这就意味着允许多个文件中定义同名的const变量,实际就等同于分别在文件中定义了独立的变量。举例如下:
main.cpp中定义了const变量MainSize:
#include <iostream>
using namespace std;
extern void test();
const int MainSize = 100;
int main()
{
int MainVal = MainSize;
std::cout << "MainVal = " << MainVal << std::endl;
test();
system("pause");
return 0;
}
test.cpp中也定义了const变量MainSize:
#include <iostream>
const int MainSize = 200;
void test()
{
int TestVal = MainSize;
std::cout << "TestVal = " << TestVal << std::endl;
}
运行后的结果:
- 那么,如何做到多个文件中使用同一个const变量呢?也就是说,只在一个文件中定义const,而在其他文件中声明并使用它。解决方案是使用extern关键字,但是和一般的变量不同,
必须在定义和声明处都加上extern
。
main.cpp中定义了extern const变量MainSize:
#include <iostream>
using namespace std;
extern void test();
extern const int MainSize = 100;
int main()
{
int MainVal = MainSize;
std::cout << "MainVal = " << MainVal << std::endl;
test();
system("pause");
return 0;
}
test.cpp中声明了const变量MainSize:
#include <iostream>
extern const int MainSize;
void test()
{
int TestVal = MainSize;
std::cout << "TestVal = " << TestVal << std::endl;
}
运行结果:
2.const 的引用
非常量引用
指向一个常量对象
是不允许的。因为常量对象本就意味则不变,若是允许此语法,那不就可以改变常量对象了吗!
const int MainVal = 100;
const int& rMainVal = MainVal; //正确
int &rMainVal2 = MainVal;//error:无法从“const int”转换为“int &”
- 初始化
常量引用(对const的引用)
时,允许用任意表达式作为初始值,只要任意表达式能转换为引用类型
。
int i = 42;
const int& r1 = i; //允许将常量引用绑定到一个普通int对象上
const int& r2 = 55; //正确
const int& r3 = r1*2; //正确
为什么C++会允许上述操作?原因在于编译器在编译的过程中,会生成一个const的临时变量,最后我们要的引用实际都指向这个临时变量。下面请看C++ primer 第5版中给出的例子:
结合上面的描述,我们也不难想到,为什么下面的初始化不行:(因为若是允许,那么修改ri或r3的值只是修改了临时变量,并没有改变dval和r1的值,而我们的目的就是改变其值
,所以C++把这种行为定为非法)
int i = 42;
double dval = 3.14;
int& r1 = i; //正确,标准的引用
int &ri = dval; //错误
int& r3 = r1*2; //错误
- 实例
#include <iostream>
using namespace std;
int main()
{
int i = 42;
const int& r1 = i;
const int& r2 = 55;
const int& r3 = r1 * 2;
std::cout << "r2 = " << r2 << std::endl;
std::cout << "&i = " << &i << " ; " << "i = " << i << std::endl;
std::cout << "&r1 = " << &r1 << " ; " << "r1 = " << r1 << std::endl;
std::cout << "&r3 = " << &r3 << " ; " << "r3 = " << r3 << std::endl;
std::cout <<"改变i值后"<< std::endl;
i = 50;
std::cout << "&i = " << &i << " ; " << "i = " << i << std::endl;
std::cout << "&r1 = " << &r1 << " ; " << "r1 = " << r1 << std::endl;
std::cout << "&r3 = " << &r3 << " ; " << "r3 = " << r3 << std::endl;
const int& r4 = r1 * 2;
std::cout << "&r4 = " << &r4 << " ; " << "r4 = " << r4 << std::endl;
system("pause");
return 0;
}
打印结果:
2.1const 指针的引用
前面我们有将常量引用指向非常量,如下
int i = 42;
const int& r1 = i; //允许将常量引用绑定到一个普通int对象上
那么,对指针是否如此呢?看下面的例子:
int a = 10;
int *p = &a;
const int* &rp = p;
最后一句是否正确?答案是否定的,因为尽管初始化常量引用(对const的引用)时,允许用任意表达式作为初始值,但我们不能忘了只要任意表达式能转换为引用类型
这句话,p是一个指针,它只能转换为常量指针,所以正确的做法是:
int* const &rp = p;
3.常量指针和指向常量的指针
3.1. 常量指针
3.2. 指向常量的指针
3.3. 两者结合
3.4. 如何区分常量指针和指向常量的指针
- 常量指针
顾名思义,说明指针是个常量,而指针代表地址,所以常量指针是不能改变指向的指针
。
int errNumb = 0;
int myerrNumb = 1;
int *const curErr = &errNumb; //定义常量指针
curErr = &myerrNumb;//错误:不能给常量赋值
- 指向常量的指针
既然指向常量,当然不能改变其值,但可改变指向
。
但是请注意:仅仅只是不能通过指针修改,但可以通过变量修改
。如
double p2 = 3.1415;
const double *cptr = &p2;
*cptr = 1.1111;
是错位的;但p2 = 1.1111
是正确的。
const double pi = 3.14;
const double *cptr = π //定义指向常量的指针
*cptr = 3.1415;//错误:不能给常量赋值
double pi2 = 3.1415;
cptr = &pi2;//改变指向,指向一个非常量对象
std::cout << *cptr << std::endl;
//通过变量修改cptr指向地址的值
pi2 = 1.111;
std::cout << *cptr << std::endl;
打印结果:
- 两者结合
既:指向一个常量对象的常量指针。兼具两者的特性:既不能改指向,也不能改值
。
如何区分常量指针和指向常量的指针
int *const curErr = &errNumb; //常量指针
const double *cptr = π //指向常量的指针
看const修饰谁,第一个修饰的curErr,它存的是地址,当然是指向不变;第二个修饰*cptr,修饰的是一个值,当然是不能改变值。