Effective C++ 条款03:尽可能使用const

const告诉编译器某个值不能是变化的。

修饰指针

const修饰指针的时候,只区分在*前还是*后。在前面表示指针常量,其指向的值无法通过这个指针改变;在后面表示常量指针,表示这个指针无法指向别的对象,但可以通过该指针修改该对象的值。

int a = 10;
const int *p1 = &a;
int const *p2 = &a;
int * const p3 = &a;
const int * const p4 = &a;
int const * const p5 = &a;

// equals to
const int *p1 = &a;
int* const p2 = &a;
const int * const p3 = &a;

下面以STL中的迭代器作为说明。STL中有两种迭代器,普通的iterator和const_iterator。const_iterator类似于const int *p 这种指针常量。即不能通过const_iterator修改容器内成员的值。

std::vector<int> vec;
std::vector<int>::const_iterator citer = vec.begin();
*citer = 10;	// wrong
citer++;		// right

相反,如果我们希望迭代器固定指向某一个值,就需要在它前面加上const

const std::vector<int>::iterator iter = vec.begin();
iter++;		// wrong
*iter = 10	// right

修饰函数

函数返回值

令函数返回一个常量可以避免某些意外。例如重载*时返回const值。

class Rational;
const Rational operator*(const Rational& lhs, const Rational& rhs);

我们定义了一个Rational类,重载了乘法操作符。如果我们将返回值定义为const那么这种写法编译器就会报错

Rational a, b;
// assigned value for a and b
...

// error
a * b = c;

// but this is our attention
a * b == c;

这种写法虽然没有任何意义,但是可能我们本来是想判断a * b后是不是等于c的。这样编译器就可以帮助我们纠正这个错误。

成员函数

const对象只能调用const成员函数。

设置一个const的成员函数,再重载一个non-const的版本。这样const对象就会调用const 的版本,而non-const的对象就会调用non-const的版本。

看个例子

class TextBlock {
public:
    TextBlock(): text("null"){}
    const char& operator[](size_t position) const 
    {return text[position];}
    char& operator[](size_t position)
    {return text[position];}
    
private:
    string text;
};

int main(){
    TextBlock a;
    const TextBlock const_a;
    a[0] = 'a';			// valid
    const_a[0] = 'b';	// invalid
}

这里我们定义了个TextBlock类,写了两个版本的[]重载。很显然,如果一个TextBlock是const的,那么自然取值以后我们也不希望它被修改,因此const版本的操作符重载需要返回一个const char&

此外,顺带一提的是在non-const版本中,返回值也必须是char&。因为只有返回了引用,我们的修改才能真正作用到类中的数据上。而且如果你不写引用编译器会报错。

后面还有一部分内容下次再补好了= =

posted @ 2021-06-21 20:10  Destiny233  阅读(56)  评论(0)    收藏  举报