首页 > 代码库 > Effective C++ iterm3

Effective C++ iterm3

条款三

--17/1/16

这个条款主要是介绍了const在c++的各个应用,看完之后真的是受益匪浅。

(1)首先const的修饰可以确保指针或者指向的东西是不是const,和我们在条款二看到的常量指针和指针常量类似,一下是具体定义:

T * const:const pointer,non-const data 也就是我们所说的指针常量;

const T *:non-const pointer,const data 也就是我们所说的常量指针;

值得注意的一点是写在类型前和类型后是一样的,也就是const T* p和T const*p是一样的,都是常量指针,T是不变的对象。

 

在STL里面的指针也有类似的形式:

a.为迭代器声明指针,指的是T*const,也就是不允许改变指针指向的地址,写法如下:

const std::map<int,int>::iterator it = mp.begin();

b.希望仅是迭代来遍历想要的内容,不允许修改具体容器里面的值,也就是const T*这时候需要的是STL提供const_iterator,写法如下:

std::map<int,int>::const_iterator it = mp.begin();

以上就是const在指针和迭代器的一个重要的应用。

 

(2)const在函数声明的应用也是应用广泛并且要提高注意的地方。令函数返回一个常量值可以提高安全性和高效性。比如这样的句子是会通过编译的:

 

 1 class R {
 2 public:
 3   R() {}
 4 };
 5 
 6 R operator * (const R& l, const R& r) {
 7   R t;
 8   return t;
 9 }
10 
11 int main() {
12   R a, b, c;
13   (a * b) = c;
14   return 0;
15 }

 

虽然这样写脑洞大了点,但是这是一个不可被忽视的问题,将函数声明为const能够增加安全性同时也可以被编译器捕捉这样的“无聊之举”?

 

(3)const成员函数中的应用是本条款花费大篇来通说的内容,我们希望这个成员函数不可修改类的相关值,我们会为这个函数加上const的字样。可以依据const与否来进行重载,const成员调用const函数,non-const调用non-const版,这个在Essential c++也提到过相关知识。

这时候作者就讨论两个派别的const成员函数:

1)bitwise constness,要求每一位的是constness,也就是const函数里面不允许有任何的修改操作,所以编译器着重检查的是类似赋值的操作。

下面这段代码却不是真正意义上的bitwise constness

 1 class R {
 2 
 3 public:
 4 
 5   R(const char *p) {
 6 
 7     str = new char[strlen(p) + 1];
 8 
 9     strcpy(str, p);
10 
11  }
12 
13  char& operator [] (int _index) const {
14 
15   return str[_index];
16 
17  }
18 
19  void print() const {
20 
21   printf("%s\n", str);
22 
23  }
24 
25 private:
26 
27   char *str;
28 
29 };
30 
31  
32 
33 int main() {
34 
35   R r("zhenhao");
36 
37   r.print();//输出 zhenhao
38 
39   char *p = &r[0];
40 
41   *p = h;
42 
43   r.print();//输出 hhenhao
44 
45   return 0;
46 
47 }

 

2)因此第二种就是logical constness一个const成员函数是可以修改里面的相关变量的,也就是逻辑上是“不可变的”就好了。这个问题在Essential C++里面就特别讨论过,使用mutable关键字将你想要放在const成员函数里面的变量可以变,而不是所有变量都不能变。

最后作者做了一个总结我觉得不错:编译器严格实行bitwise constness,但是写程序是应该遵守的是logical constness。

 

(4)巧妙使用转换避免const和non-const的重复,当我们实现两种版本的函数时,如果实现机制没有什么区别,那么可以利用转换来避免这个重复。这个避免的实现在non-const的成员函数内,将non-const成员转换成const(安全的),然后调用相应的const函数之后返回的值利用const_cast来进行转换回来即可。注意强调的是不可以将const转换成non-const,因为这不仅在逻辑上不成立,而且实现起来也麻烦。

Effective C++ iterm3