条款03:尽可能的使用const关键字
一、先写写const
的用法
const的位置 | 含义 |
---|---|
const int a = 2; |
a 的值不能被修改 |
const int *p = &a; |
p 不会被修改,即p 这个指针不会指向其他地方了 |
int* const p = &a; |
即p 这个指针指向的值不可以更改 |
const int* const p = &a; |
即p 这个指针指向的值和自己都不能发生更改。 |
修饰类成员的const
方法
const
还可以放在类方法后边,表示此函数承诺不修改类成员变量的值,比如:
class B {
int num;
void show() const {
std::cout << num << std::endl;
}
};
编译器会执行一种被称为bitwise的检查,检查是否存在修改内部值的情况。至于到了我们真正使用的情况下,我们可能不会遵循这个bitwise的检查方式。
比如,如果我们在类的成员中增加了一个作为缓存的变量值,比如:
class B {
vector<int> nums;
int numLen;
bool numLenValid;
int getLen() const {
if (numLenValid) {
return numLen;
}
numLen = nums.size();
numLenValid = numLen;
return numLen;
}
};
这里好像有点咸鱼,但是假如我们把
nums.size()
替换成一个很费事的操作,那么这个缓存变量就体现出了它的价值了。
明显getLen()
从语义上讲是不会修改类内的元素的值的,因为我们直接写成return nums.size()
当然也是OK的,但是在这样的场景下它又确实修改了类内元素的值。此时我们可以使用mutable
关键字。
class B {
vector<int> nums;
mutable int numLen;
mutable bool numLenValid;
int getLen() const {
if (numLenValid) {
return numLen;
}
numLen = nums.size();
numLenValid = numLen;
return numLen;
}
};
此时的编译就没有问题了。
使用non-const
调用const
以完成代码复用
两个函数的cosnt
修饰不同时,他们已经是两个不同的函数了。如果我们想要两个只有const
修饰不同的函数之间共享大部分相同的代码时,需要用non-const
的函数调用const
的函数,而不是反过来。
因为我们已经承诺在
const
函数里不修改内部的值,所以使用const
调用一个没有任何承诺的non-const
是一种不好的行为。而反过来则没有任何顾虑。
class TextBlock{
public:
const chars operator[] (std::size_t position) const
// 一如既往
{
return text[position];
}
char&operator[](std::size_t position)
//现在只调用const op[]
{
return const_cast<char&>(
//将op[]返回值的const转除
static cast<const TextBlock>(*this)
//为*this加上const
[position] //调用const op[]
);
}
};