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

声明:

  1. 文中内容收集整理自《Effective C++(中文版)第三版》,版权归原书所有。
  2. 本内容在作者现有能力的基础上有所删减,另加入部分作者自己的理解,有纰漏之处敬请指正。

条款03:尽可能使用const

Use constwhenever possible.

const是个很奇妙的东西,自己在编程开发中深有体会,它告诉编译器和其他程序员某值应该保持不变。

const语法虽然变化多端,但并不高深莫测。

  • 如果关键字const出现在*之前,代表被指物是常量;如果出现在*右边,表示指针自身是常量
char greeting[] = "Hello";
char *p = greeting; //non-const pointer, non-const data
const char *p = greeting; //non-const pointer, const data
char * const p = greeting; //const pointer, non-const data
const char * const p = greeting; //const pointer, const data
  • 如果被指物是常量,则const关键字放在类型前以及放在类型后*前,两种写法意义相同。
void f1(const Widget *pw);
void f1(Widget const *pw);

STL迭代器的作用类似于T*指针。如果希望迭代器所指的东西不被改动(即希望STL模拟一个const T*指针),则使用const_iterator即可。

const最具威力的用法是面对函数声明时的应用。

  • 令函数返回一个const,往往可以降低因客户原因造成的意外,而又不至于放弃安全性和高效性。eg:
//考虑有理数的operator*声明式
class Rational{…};
const Rational Rational::operator*(const Rational &lhs, const Rational &rhs);

//将返回值声明为const可避免这种赋值情况的发生
Rational a, b, c;
(a*b) = c;//这是个没意思的动作

const成员函数

将const实施与成员函数的目的,是为了确认该成员函数可作用于const对象上

  • const成员函数用放置于参数列表后的const标识符标识。
  • 两个成员函数,如果只是常量性不同,可以被重载。
class TestBlock
{
private:
	string text;
public:
	const char& operator[](size_t position) const
	{
		return text[position];
	}
	char& operator[](size_t position)
	{
	return text[position];
	}
};

TestBlock tb("Hello");
const TestBlock ctb("World");
tb[0] = 'x'; //正确,写一个nonst-const类型
ctb[0] = 'x'; //错误,写一个const类型
  • 上述错误只因operator[]的返回类型所致
  • 注意:两个operator[]的返回类型都为reference to char,是因为如果函数的返回类型是个内置类型,那么改动函数返回值从来就不合法。或者即使合法,C++以by-value返回对象这一事实意味着并没有改动tb.text[0]自身,而是改动的一个副本。
  • const成员函数不可以更改对象内任何non-static成员变量,eg:
class CTextBlock
{
public:
	size_t length() const;
private:
	char *pText;
	size_t textLength;
	bool lengthIsValid;
};
size_t CTextBlock::length() const
{
	if (!lengthIsValid)
	{
		textLength = strlen(pText); //错误,表达式必须是可修改的左值
		lengthIsValid = true; //错误,表达式必须是可修改的左值
	}
	return textLength;
}
  • 解决以上问题只需要利用C++的一个与const相关的摆动场:mutable(可变的),mutable会释放掉no-static成员变量的const约束。
mutable size_t textLength;
mutable bool lengthIsValid;

在const和non-const成员函数中避免重复

两个版本的operator[]通常会有代码重复,真正该做的是实现operator[]的机能一次并使用它两次。也就是说,必须令其中一个调用另一个。本例中,const operator[]完全做掉了non-const版本该做的一切,唯一不同的是其返回类型多了一个const。这种情况下将返回值的const移除是安全的,因为不论谁调用non-const operator[]都一定首先有个non-const对象。所以令non-const版本的调用const版本的是一个避免代码重复的办法。

class TestBlock
{
private:
	string text;
public:
	...
	const char& operator[](size_t position) const
	{
		...
		...
		...
		return text[position];
	} //const版本和之前一致

	char& operator[] (size_t position)
	{
		return const_cast<char&>(static_cast<const TestBlock&>(*this)[postion]);
	}
};

代码解析:

  1. const版本和之前一致;
  2. 我们打算让non-const版本调用const版本,如果non-const版本单纯调用operator[],会导致递归调用,因此要指出调用的是const版本;
  3. 此处将*this从起原始类型TextBlock&转型为const TextBlock&,语法为static_cast<const TextBlock&>(*this),这是第一次转型;
  4. 第二次转型为从const operator[]的返回值中移除const,语法为const_cast<char&>()。

需要注意的是,反向做法——即令const版本调用non-const版本是一种错误行为,因为对象可能被改动。const成员函数承诺绝对不改变对象的逻辑状态,而non-static成员函数可以对对象做任何操作。

请记住:

将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。

编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”。

党const和non-const成员函数有实质等价的实现时,令non-const版本调用const版本可避免代码重复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值