Effective C++学习笔记(2)

Term03: Use const whenever possible.


这个条款总结了const关键字的用法,使用const修饰可以大大地增强程序的健壮性。


1.常量指针与指针常量的区别

简单的原则,const在*左边,表示被指物是常量;在*右边,表示指针是常量。例如:

const int * a;  //const->int
int const * b;  //const->int
int * const c;  //const->*

a和b都是指向int型常量的指针,指针为变量;而c是指向int型变量的指针,指针为常量。


2.STL迭代器使用const关键字

从某种程度上讲,迭代器类似于指针,不过迭代器的const用法不同。例如:

const std::vector::iterator i;  //const->iterator
std::vector::const_iterator j;  //const->int

也就是说,const关键字使得iterator位置不能动,iterator指向的元素可以写;而const_iterator指向的元素只读,但位置可以动。


3.函数返回值用const修饰

这里举的例子是对于*等操作符,内置类型如int是不允许表达式被赋值的,例如你不能写:

int a=2,b=3;
a*b=5;

但如果是自定义类的对象则不存在这个限制,因为*运算符重载后被视为成员函数,返回的对象使用的=运算符也是经过重载的成员函数,不受右值语法的限制。为了保持和内置类型一样的限制,将*运算符的返回值限定为const,则可以避免这种问题。


4.const成员函数

const修饰成员函数写在成员函数声明的右侧,与3中提到的修饰返回值的const写在左侧相对应。

const修饰成员函数的意义是明确了函数的只读属性,不允许改变成员变量。

非常量对象可以调用自己的const或非const成员函数,而常量对象只能调用const成员函数。

成员函数可以通过const特性进行重载,重载之后的成员函数,常量对象调用const成员,非常量对象调用非const成员。

关于const重载,书中举了一个例子。一个自定义的字符串类CTextBlock,重载[]运算符,我们希望CTextBlock的常量对象取下标返回的是字符常量,变量对象取下标则是字符变量。那么const重载保证了常量对象可以调用[]运算符,而返回值为const char&则保证了返回的是字符常量。同时非const重载的[]返回的是字符变量。

我们知道如果一个对象是常量,那么它的成员也是常量。但这种常量特性对于指针成员有个尴尬的问题,那就是即使指针是常量,仍然可以利用这个指针来改变它所指向的内容,而它所指向内容的常量性需要另外声明。而实际上我们一般的业务逻辑是更加关注指向内容的常量性,典型的应用是字符串。这两种常量性的概念分别称为bitwise constness和logical constness。

对于bitwise constness,我们可以用const修饰返回值的方式防止返回指针或引用破坏对象的常量性。而对于logical constness,有些成员需要可变,例如取长度,而我们想只要不是外部赋值就可以了。这种情况下,如何让const成员函数访问的成员可变,可以考虑对成员变量使用mutable修饰,这样就可以在const成员函数里变化了。

const重载成员函数可能会导致代码重复,解决的方法是用非const成员调用const成员。代码如下:

return const_cast(static_cast(*this)[position]);

使用const TextBlock&强制转换*this已使其具有constness,则调用[]即为const版本,然后返回值使用const_cast去除constness。

你可能感兴趣的:(Effective C++学习笔记(2))