const是c
![](/icons/54675jiajia.gif)
当中很有特色
![](/icons/54675de.gif)
![](/icons/54675yi.gif)
个语言功能
![](/icons/54675dou.gif)
它限制了对数据
![](/icons/54675de.gif)
操作
![](/icons/54675dou.gif)
还限制了类成员
![](/icons/54675hanshu.gif)
![](/icons/54675de.gif)
行为
![](/icons/54675dou.gif)
而且是对c
![](/icons/54675jiajia.gif)
![](/icons/54675de.gif)
引用类型
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
参数和返回值这个功能
![](/icons/54675de.gif)
有益补充
![](/icons/54675dou.gif)
c
![](/icons/54675jiajia.gif)
![](/icons/54675chengxu.gif)
员应该时时有意识地正确使用const关键字
![](/icons/54675dou2.gif)
const对于变量来说
![](/icons/54675dou.gif)
是
![](/icons/54675yi.gif)
个要求
![](/icons/54675dou.gif)
而对于
![](/icons/54675hanshu.gif)
来说
![](/icons/54675dou.gif)
是
![](/icons/54675yi.gif)
个承诺
![](/icons/54675dou.gif)
对它所操作
![](/icons/54675de.gif)
变量
![](/icons/54675de.gif)
承诺
![](/icons/54675dou2.gif)
由于const
![](/icons/54675de.gif)
使用场合和使用对象很多
![](/icons/54675dou.gif)
要正确地使用它还是需要用
![](/icons/54675yi.gif)
番心思
![](/icons/54675de.gif)
const在
![](/icons/54675yi.gif)
下
![](/icons/54675yi.gif)
些地方使用:
首先它可以修饰
![](/icons/54675yi.gif)
个变量
![](/icons/54675dou.gif)
此时这个const是这个变量
![](/icons/54675de.gif)
![](/icons/54675yi.gif)
个要求---它不可以被修改
![](/icons/54675dou.gif)
所以这个变量必须在
![](/icons/54675chushi.gif)
化
![](/icons/54675de.gif)
时候被赋值
![](/icons/54675dou.gif)
![](/icons/54675chushi.gif)
化的后就不能赋值了
![](/icons/54675dou.gif)
是
![](/icons/54675yi.gif)
个只读
![](/icons/54675de.gif)
变量
![](/icons/54675dou.gif)
见本文末尾
![](/icons/54675de.gif)
例子(2)
![](/icons/54675dou2.gif)
这意味着它不可以以任何方式被赋值
![](/icons/54675dou.gif)
包括不能做赋值表达式
![](/icons/54675de.gif)
左值
![](/icons/54675dou.gif)
同时不可以把它传递给那些没有承诺不更改它
![](/icons/54675de.gif)
值
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
那么
![](/icons/54675hanshu.gif)
如何做这个承诺呢
![](/icons/54675dou.gif)
看第 5段
![](/icons/54675dou2.gif)
如果
![](/icons/54675yi.gif)
个
![](/icons/54675int.gif)
类型变量i是const
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
那么它
![](/icons/54675de.gif)
地址&i也是const
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
从(3)中可以看出
![](/icons/54675dou.gif)
&i只能赋值给const
![](/icons/54675de.gif)
指针变量p而不可以赋值给q
![](/icons/54675dou.gif)
![](/icons/54675yinwei.gif)
我们可以通过赋值给*q而更改它所指向
![](/icons/54675de.gif)
变量i. 从这里我们可以看到
![](/icons/54675dou.gif)
上述声明表示我们不可以通过p修改它所指向
![](/icons/54675de.gif)
变量
![](/icons/54675de.gif)
值
![](/icons/54675dou.gif)
也就是说*p也是
![](/icons/54675yi.gif)
个常量了
![](/icons/54675dou.gif)
所以 *p = 5 这样
![](/icons/54675de.gif)
表达式是
![](/icons/54675cuowu.gif)
![](/icons/54675de.gif)
(4)
![](/icons/54675dou2.gif)
要注意
![](/icons/54675de.gif)
是
![](/icons/54675dou.gif)
p作为
![](/icons/54675yi.gif)
个变量
![](/icons/54675dou.gif)
它自身是可以修改
![](/icons/54675de.gif)
(6)
![](/icons/54675dou.gif)
p
![](/icons/54675de.gif)
声明当中
![](/icons/54675de.gif)
const要求不可以通过p更改它所指向
![](/icons/54675de.gif)
值
![](/icons/54675dou.gif)
是p对它所指向
![](/icons/54675de.gif)
变量
![](/icons/54675de.gif)
承诺
![](/icons/54675dou2.gif)
当它所指向
![](/icons/54675de.gif)
变量不需要这样
![](/icons/54675de.gif)
承诺时
![](/icons/54675dou.gif)
p自然仍然可以指向那个变量(6)
![](/icons/54675dou.gif)
但是(7)仍然是
![](/icons/54675cuowu.gif)
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
![](/icons/54675yinwei.gif)
p有承诺不可以改变它所指向
![](/icons/54675de.gif)
变量
![](/icons/54675de.gif)
值
![](/icons/54675dou2.gif)
另外
![](/icons/54675dou.gif)
如果我们想要求p指针变量自身也不可以修改
![](/icons/54675dou.gif)
那我们应该如(9)中所做
![](/icons/54675dou.gif)
并且注意此时r必须在
![](/icons/54675chushi.gif)
化时候赋值
![](/icons/54675dou.gif)
否则它就不可能再被赋值了(10)
![](/icons/54675dou2.gif)
而从(11)中我们可以看出
![](/icons/54675dou.gif)
指针变量k要求它自身是只读
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
但是没有承诺不可以通过它来修改它所指向
![](/icons/54675de.gif)
变量
![](/icons/54675dou.gif)
因而不可以把&i赋值给它
当
![](/icons/54675yi.gif)
个对象例子被const修饰后
![](/icons/54675dou.gif)
它自身
![](/icons/54675de.gif)
状态在
![](/icons/54675chushi.gif)
化的后就不可以修改了
![](/icons/54675dou.gif)
这时候不仅上面
![](/icons/54675de.gif)
约束必须成立
![](/icons/54675dou.gif)
而且我们不可以
![](/icons/54675diaoyong.gif)
它
![](/icons/54675de.gif)
成员
![](/icons/54675hanshu.gif)
![](/icons/54675dou.gif)
![](/icons/54675yinwei.gif)
它
![](/icons/54675de.gif)
成员
![](/icons/54675hanshu.gif)
可能会修改它
![](/icons/54675de.gif)
状态
![](/icons/54675dou.gif)
除非那个成员
![](/icons/54675hanshu.gif)
承诺不会修改this对象
![](/icons/54675de.gif)
状态
![](/icons/54675dou2.gif)
而承诺
![](/icons/54675de.gif)
方式至少是在
![](/icons/54675hanshu.gif)
签名末尾加上"const"
![](/icons/54675dou.gif)
如(12)所示
![](/icons/54675dou2.gif)
而如果这个
![](/icons/54675hanshu.gif)
要返回
![](/icons/54675yi.gif)
个非mutable
![](/icons/54675de.gif)
数据成员
![](/icons/54675de.gif)
引用
![](/icons/54675de.gif)
话
![](/icons/54675dou.gif)
那么返回类型必须加上const表示那个返回
![](/icons/54675de.gif)
引用不可以被用于修改对象
![](/icons/54675de.gif)
状态
![](/icons/54675dou.gif)
这样这个成员
![](/icons/54675hanshu.gif)
才完整地承诺了它不会被用于修改对象
![](/icons/54675de.gif)
状态(13)
![](/icons/54675dou.gif)
否则
![](/icons/54675dou.gif)
就不可以说它是
![](/icons/54675yi.gif)
个常量成员
![](/icons/54675hanshu.gif)
(14)
![](/icons/54675dou2.gif)
事实上
![](/icons/54675dou.gif)
如果
![](/icons/54675yi.gif)
定要返回数据成员
![](/icons/54675de.gif)
引用(比如拷贝构造
![](/icons/54675de.gif)
代价很大时)
![](/icons/54675dou.gif)
那么强烈建议返回const引用
![](/icons/54675dou.gif)
以便禁止修改这个数据成员
![](/icons/54675dou.gif)
否则将严重违反类
![](/icons/54675de.gif)
封装性
![](/icons/54675dou.gif)
这种违反可能带来暂时
![](/icons/54675de.gif)
编码方便性
![](/icons/54675dou.gif)
但是长期来看
![](/icons/54675dou.gif)
![](/icons/54675yi.gif)
定会吃苦头
![](/icons/54675de.gif)
注意在(12)中
![](/icons/54675dou.gif)
虽然返回了数据成员message_
![](/icons/54675dou.gif)
但是我们返回
![](/icons/54675de.gif)
是它
![](/icons/54675de.gif)
![](/icons/54675yi.gif)
个copy而不是那个对象自身
![](/icons/54675dou.gif)
所以get_message
![](/icons/54675kh.gif)
![](/icons/54675hanshu.gif)
不可能被用于修改message_数据成员
![](/icons/54675dou.gif)
而(12.1)错就错在它返回了message_
![](/icons/54675de.gif)
引用
那么什么是
![](/icons/54675yi.gif)
个对象
![](/icons/54675de.gif)
状态呢
![](/icons/54675dou.gif)
默认是这个对象
![](/icons/54675de.gif)
所有数据成员
![](/icons/54675dou.gif)
但是在有
![](/icons/54675yi.gif)
些情景下
![](/icons/54675dou.gif)
![](/icons/54675yi.gif)
个对象
![](/icons/54675de.gif)
某些成员变量可能对于它
![](/icons/54675de.gif)
状态没有决定作用
![](/icons/54675dou.gif)
这完全决定于类
![](/icons/54675de.gif)
设计者
![](/icons/54675dou2.gif)
如果类Foo中有这样
![](/icons/54675de.gif)
成员变量
![](/icons/54675de.gif)
话
![](/icons/54675dou.gif)
我们需要把它声明为mutable
![](/icons/54675dou.gif)
表示即使
![](/icons/54675yi.gif)
个Foo
![](/icons/54675de.gif)
例子是常量
![](/icons/54675dou.gif)
我们也可以修改这个成员
![](/icons/54675dou.gif)
同理
![](/icons/54675dou.gif)
类 Foo
![](/icons/54675de.gif)
那些承诺不修改对象状态
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
也可以修改这个成员变量(12)
![](/icons/54675dou2.gif)
类当中也可以有const
![](/icons/54675de.gif)
数据成员
![](/icons/54675dou.gif)
它也像独立
![](/icons/54675de.gif)
const变量
![](/icons/54675yi.gif)
样
![](/icons/54675dou.gif)
完全不可以以任何方式修改它
![](/icons/54675de.gif)
值
![](/icons/54675dou.gif)
所以它必须在类
![](/icons/54675de.gif)
构造
![](/icons/54675hanshu.gif)
![](/icons/54675de.gif)
![](/icons/54675chushi.gif)
化列表中被
![](/icons/54675chushi.gif)
化
![](/icons/54675dou.gif)
在构造
![](/icons/54675hanshu.gif)
体中
![](/icons/54675chushi.gif)
化是不可以
![](/icons/54675de.gif)
(15)
那么
![](/icons/54675yi.gif)
个独立
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
或者类
![](/icons/54675de.gif)
成员
![](/icons/54675hanshu.gif)
如何承诺不会修改传入
![](/icons/54675de.gif)
变量自身呢?对于诸如(16)这样
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
![](/icons/54675dou.gif)
它们不会面临这个问题
![](/icons/54675dou.gif)
![](/icons/54675yinwei.gif)
所有
![](/icons/54675de.gif)
参数都是在传值
![](/icons/54675dou.gif)
在(17)例子中
![](/icons/54675dou.gif)
实际参数m, n传入
![](/icons/54675hanshu.gif)
add后
![](/icons/54675dou.gif)
它们
![](/icons/54675de.gif)
值分别被赋值给其形参a和b
![](/icons/54675dou.gif)
的后两个实际参数m, n就和
![](/icons/54675hanshu.gif)
add无关了
![](/icons/54675dou.gif)
自然add不会修改到m和n
![](/icons/54675de.gif)
值
![](/icons/54675dou2.gif)
真正需要面对这个问题
![](/icons/54675de.gif)
是那些传递引用
![](/icons/54675de.gif)
![](/icons/54675hanshu.gif)
![](/icons/54675dou.gif)
这里和下文
![](/icons/54675de.gif)
引用是广义
![](/icons/54675de.gif)
引用
![](/icons/54675dou.gif)
包括& 修饰
![](/icons/54675de.gif)
引用类型变量
![](/icons/54675dou.gif)
以及通过传递指针值来“引用”到实际参数本身
![](/icons/54675de.gif)
情形
![](/icons/54675dou.gif)
如例子(18). 当
![](/icons/54675yi.gif)
个
![](/icons/54675hanshu.gif)
![](/icons/54675de.gif)
参数中有某个参数是在传递引用
![](/icons/54675dou.gif)
那么
![](/icons/54675dou.gif)
如果这个
![](/icons/54675hanshu.gif)
确实不需要修改那个实际参数本身
![](/icons/54675de.gif)
值
![](/icons/54675dou.gif)
那么
![](/icons/54675yi.gif)
定要把那个参数声明为const
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
这样
![](/icons/54675dou.gif)
不仅可以传入可读可写
![](/icons/54675de.gif)
变量作为那个实参
![](/icons/54675dou.gif)
而且可以传入
![](/icons/54675yi.gif)
个const变量
![](/icons/54675dou.gif)
![](/icons/54675yinwei.gif)
我们已经承诺了不会修改那个实际参数本身
![](/icons/54675de.gif)
值(19)
![](/icons/54675dou2.gif)
在
![](/icons/54675hanshu.gif)
参数中传递引用常常是很有效
![](/icons/54675de.gif)
---如果对象拷贝构造
![](/icons/54675de.gif)
代价很大
![](/icons/54675dou.gif)
或者要操纵实际参数自身---但是
![](/icons/54675yi.gif)
定要在可能
![](/icons/54675de.gif)
时候
![](/icons/54675dou.gif)
声明引用为const
![](/icons/54675de.gif)
![](/icons/54675dou2.gif)
const在类中还有
![](/icons/54675yi.gif)
个用处---用于定义静态常量数据成员
![](/icons/54675dou.gif)
如例子(20)
在设计类
![](/icons/54675de.gif)
时候
![](/icons/54675dou.gif)
必须考虑清楚哪些数据成员应该是const
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
![](/icons/54675chushi.gif)
化后就不可以再修改;哪些数据成员是mutable
![](/icons/54675de.gif)
![](/icons/54675dou.gif)
对对象
![](/icons/54675de.gif)
状态定义没有影响;哪些成员
![](/icons/54675hanshu.gif)
不会修改对象
![](/icons/54675de.gif)
状态
![](/icons/54675dou.gif)
应该声明为常量
![](/icons/54675hanshu.gif)
![](/icons/54675dou.gif)
不会修改对象状态;那些
![](/icons/54675hanshu.gif)
不会修改引用参数
![](/icons/54675de.gif)
值
![](/icons/54675dou.gif)
可以是const
![](/icons/54675de.gif)
![](/icons/54675dou2.gif)
在应该和可以使用const
![](/icons/54675de.gif)
地方
![](/icons/54675yi.gif)
定使用它
const
![](/icons/54675de.gif)
效果可能被
![](/icons/54675yi.gif)
下
![](/icons/54675yi.gif)
些语言功能所抵消:1. const_cast<> 2. C风格
![](/icons/54675de.gif)
强制类型转换
![](/icons/54675dou2.gif)
在设计良好
![](/icons/54675de.gif)
代码中
![](/icons/54675dou.gif)
我们要非常小心地使用这种抵消const功能
![](/icons/54675de.gif)
语言功能
![](/icons/54675dou.gif)
特别是第2种
![](/icons/54675dou.gif)
应该被禁用
![](/icons/54675dou2.gif)
例如
![](/icons/54675dou.gif)
类
![](/icons/54675de.gif)
使用者看到
![](/icons/54675hanshu.gif)
引用参数
![](/icons/54675de.gif)
const属性
![](/icons/54675dou.gif)
会放心地把自己
![](/icons/54675de.gif)
常量数据传入
![](/icons/54675hanshu.gif)
![](/icons/54675dou.gif)
却想不到这个承诺是假
![](/icons/54675de.gif)
![](/icons/54675dou2.gif)
这样
![](/icons/54675de.gif)
bug非常难调试
![](/icons/54675dou2.gif)
再比如
![](/icons/54675dou.gif)
![](/icons/54675yi.gif)
个const
![](/icons/54675hanshu.gif)
返回了
![](/icons/54675yi.gif)
个const
![](/icons/54675de.gif)
数据成员
![](/icons/54675de.gif)
引用
![](/icons/54675dou.gif)
但是这个
![](/icons/54675hanshu.gif)
![](/icons/54675de.gif)
![](/icons/54675diaoyong.gif)
者却使用1或者2思路方法抵消了const
![](/icons/54675de.gif)
作用
![](/icons/54675dou.gif)
那么这个对象
![](/icons/54675de.gif)
状态改变很难追踪
![](/icons/54675dou.gif)
这样
![](/icons/54675de.gif)
代码是非常危险
![](/icons/54675de.gif)
代码
![](/icons/54675dou.gif)
应该坚决地避免使用
![](/icons/54675dou2.gif)
在使用某些旧
![](/icons/54675de.gif)
c语言代码时候
![](/icons/54675dou.gif)
我们可能不得不做 第2类强制转换
![](/icons/54675dou.gif)
这是
![](/icons/54675chengxu.gif)
员应该予以足够
![](/icons/54675de.gif)
特殊标注和注释
在最新
![](/icons/54675de.gif)
C语言标准(c99)中
![](/icons/54675dou.gif)
const也被引入了
![](/icons/54675dou.gif)
可以修饰
![](/icons/54675hanshu.gif)
![](/icons/54675de.gif)
参数和返回值
![](/icons/54675dou.gif)
以及变量
![](/icons/54675dou.gif)
使用思路方法和上面相同
![](/icons/54675dou.gif)
新
![](/icons/54675de.gif)
C标准库也同步做了更新
![](/icons/54675dou.gif)
所以在C语言中
![](/icons/54675dou.gif)
也是要在可以使用const
![](/icons/54675de.gif)
地方
![](/icons/54675yi.gif)
定使用它
![](/icons/54675dou.gif)
原因也同上
(1) const
![](/icons/54675int.gif)
i = 3;
(2) i = 5; ×
(3) const
![](/icons/54675int.gif)
*p = &i; OK
![](/icons/54675int.gif)
*q = &i; ×
(4) *p = 5; ×
(5)
![](/icons/54675int.gif)
j = 6; OK
(6) p = &j; Ok
(7) *p = 5; ×
(8) j = 5; OK
(9) const
![](/icons/54675int.gif)
*const r = &i; OK
(10) r = &j; ×
(11)
![](/icons/54675int.gif)
*const k = &i; ×
![](/icons/54675class.gif)
Foo {
![](/icons/54675string.gif)
message_;
const
![](/icons/54675string.gif)
my_name_;
mutable
![](/icons/54675int.gif)
junk_;
const
![](/icons/54675static.gif)
size_t max_num_; (20)
public:
![](/icons/54675string.gif)
get_message
![](/icons/54675kh.gif)
const (12)
{
junk_ = 1; // OK
![](/icons/54675return.gif)
message_;
}
![](/icons/54675string.gif)
& get_message
![](/icons/54675kh.gif)
const; × (12.1)
const
![](/icons/54675string.gif)
& get_message_ref
![](/icons/54675kh.gif)
const (13)
{
![](/icons/54675return.gif)
message_;
}
![](/icons/54675string.gif)
& get_message_ref
![](/icons/54675kh.gif)
(14)
{
![](/icons/54675return.gif)
message_;
}
Foo
![](/icons/54675kh.gif)
: my_name("david"){} (15)
}; // Foo
![](/icons/54675int.gif)
add(
![](/icons/54675int.gif)
a,
![](/icons/54675int.gif)
b); (16)
![](/icons/54675int.gif)
m = 6, n = 7; (17)
add(m, n); (17)
void negate(
![](/icons/54675int.gif)
& a); (18)
void swap(
![](/icons/54675int.gif)
*a,
![](/icons/54675int.gif)
*b); (18)
size_t strlen(const char *); (19)
延伸阅读
最新评论