const 限定符

一、const 的初始化

   const 可以限定变量的类型,创建一种类型的常量,创建后便不能够被改变。
   因为 const 对象创建后不能够改变其值,因此 const 对象在创建时必须初始化:

	const int i = 42;		//正确,编译时初始化
	const int k;			//错误,未初始化常量
	const int ci = i;		//正确,将i的值拷贝给ci

   默认状态下,const 对象仅在文件内有效。
   要想只在一个文件定义 const 对象,而在多个文件中声明并使用它。
   解决办法是,对于 const 变量不管是声明还是定义都添加 extern 关键字,这样就只需要定义一次就行了:

	//file_1.cpp定义并初始化一个常量,该常量便能够在其他文件访问
	extern const int bufSize = 512;
	//file_1.h头文件
	extern const int bufSize;	//与file_1.cpp文件中定义的 bufSize 是同一个

   file_1.h头文件中的声明也由 extern 限定,作用是指明 bufSize 并非本文件独有,它的定义在其他问中间出现。

二、const 的引用

   引用既可以绑定到 const 对象,也可以绑定到非 cons t对象,从代码开始分析:

	int i = 512;
	const int ci = 1024;
	const int &r1 = ci;			//正确,引用还有其绑定对象都是 cosnt
	r1 = 2048;					//错误,r1 是对 const 的引用
	const int& r2 = i;			//正确,允许将 const int& 绑定到普通 int 对象上
	const int& r3 = 42;			//正确
	const int& r4 = r2 * 2;		//正确
	int &r5 = ci;				//错误,让非 const 引用绑定到 const 对象上

   从上面的代码中可以看出,允许将一个对 const 的引用绑定带非 const 的对象,字面值,甚至是表达式。
   但是,在 const 引用绑定到非 cosnt 的对象时,不能够通过该引用去修改其绑定的对象。

三、const的指针

   与引用类似,指针也可以指向 const 对象或非 const 对象。指向常量的指针不能够用于改变其所指向的对象。还是从代码开始分析:

	const double pi = 3.14;			//pi是个常量,它的值不能改
	double* ptr = π				//错误,pi 是 const 对象,要用 ptr 只是个普通指针
	const double* cptr = π		//正确,const指针 指向 const 对象
	*cptr = 3.14159;				//错误,不能通过 cptr 修改其指向的对象
	cosnt double* const cpi = π	//既不能修改其指向的对象,也不能修改指针 cpi 的指向

   从上面的代码可以看到,指针是一个对象,常量指针声明后必须初始化,并且初始化后,不能再修改它的值。并且对于 const 对象,要用常量指针才能够指向它。
   在这里 const 既能修饰其指针本身指向,也能修饰其指向的对象。修饰的是谁,就要根据cons t与*的左右来区分了。

四、顶层 const

   如上面所述,指针本来是对象,它又可以指向另一个对象。所以这里用**顶层 const 底层 const **去区分其指针本身还是所指对象,谁是常量的问题。顶层 const 表示指针本身是个常量,而底层 const 表示指针所指向的对象是 const 。
   顶层 const 可以表示任意的对象是常量,对任何数据类型都是用。底层 const 则对指针和引用等复合类型的基本类型部分有关。比较特殊的是,指针类型既可以是顶层 const 也可以是底层 const 。

	int i = 0;
	int* const p1 = &i;			//不能修改p1的值,顶层const
	const int ci = 42;			//不能修改ci的值,顶层const
	const int* p2 = &i;			//不能通过p2修改ci的值,可以改变p2的值,底层const
	int* p3 = p2;				//错误,p2是底层const,而p3不是const指针

   从上面的代码可以看到,在执行对象的拷贝操作时,顶层 const 不受什么影响;而底层 const ,却有些不可忽视的限制,拷贝和拷出的对象必须有相同的底层 const 资格,或对象的数据类型能够转换,非 const 可以转换成const(p2 = &i),但反之却不行(p3 = p2)。

五、constexpr和常量表达式

   常量表达式是指值不会改变并且在编译过程就能够得到的表达式。显然,字面值属于常量表达式,用常量表达式初始化的 const 对象也是常量表达式。C++语言中有几种情况下也是要用到常量表达式的。

	const int max_files = 20;			//常量表达式
	const int limit = max_files + 1;	//常量表达式
	int staff_size = 27;				//非常量表达式

   虽然 27 是常量,但是其数据类型只是普通 int 而非 const int,所以它不是常量表达式。
   在一个复杂系统中,很难(几乎肯定不能)分辨一个初始值到底是不是常量表达式,虽然可以定义一个 const 变量并把它的初始值设为我们认为的某个常量表达式,但在实际使用时,尽管要求如此,但常常发现初始值并非常量表达式的情况。
   C++新标准规定,允许将变量声明为 constexpr 类型以便由编译器来验证变量的初始值是否是一个常量表达式。声明为 constexpr 的变量一定是一个常量,而且必须用常量表达式初始化

	constexpr int mf = 20;			//正确,常量表达式
	constexpr int limit = mf + 1;	//正确,常量表达式
	constexpr int sz = size();		//不一定,只有当size是constexpr函数时,才正确

   尽管不能使用普通函数作为 constexpr 变量的初始值,但是新标准允许一种特殊的 constexpr 函数,这种函数应该足够简单以使得编译时就可以计算其结果
   强调一点,在 constexpr 声明中如果定义了一个指针,限定符 constexpr 仅对指针本身有效,与指针所指的对象无关:

	const int* p = nullptr;			// p 是一个指向 int 常量的指针
	constexpr int* q = nullptr;		// q 是一个指向 int 变量的常量指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值