避免 const 与非 const 成员函数之间的重复
mutable 对于“我不了解按位恒定”的情况不失为一个良好的解决方案,但是它对于所有的 const 难题并不能做到一劳永逸。举例说, TextBlock (以及 CTextBlock )中的 operator[] 不仅仅返回一个对恰当字符的引用,同时还要进行边界检查、记录访问信息,甚至还要进行数据完整性检测。如果将所有这些统统放在 const 或非 const 函数(我们现在会得到过于冗长的隐式内联函数,不过不要惊慌,在第 30 项中这个问题会得到解决)中,看看我们会得到什么样的庞然大物:
class TextBlock {
public:
...
const char& operator[](std::size_t position) const
{
... // 边界检查
... // 记录数据访问信息
... // 确认数据完整性
return text[position];
}
char& operator[](std::size_t position)
{
... // 边界检查
... // 记录数据访问信息
... // 确认数据完整性
return text[position];
}
private:
std::string text;
};
噢!天哪,这让人头疼:重复代码,以及随之而来的编译时间增长、维护成本增加、代码膨胀、等等……当然,像边界检查这一类代码是可以移走的,它们可以单独放在一个成员函数(当然是私有的)中,然后让这两个版本的 operator[] 来调用它,但是你的代码仍然有重复的函数调用,以及重复的 return 语句。
对于 operator[] 你真正需要的是:一次实现,两次使用。也就是说,你需要一个版本的 operator[] 来调用另一个。这样便可以通过转型来消去函数的恒定性。
通常情况下转型是一个坏主意,后边我将专门用一项来告诉你为什么不要使用转型(第 21 项),但是代码重复也不会让人感到有多轻松。在这种情况下, const 版的 operator[] 与非 const 版的 operator[] 所做的事情完全相同,不同的仅仅是它的返回值是 const 的。通过转型来消去返回值的恒定性是安全的,这是因为任何人调用这一非 const 的 operator[] 首先必须拥有一个非 const 的对象,否则它就不能调用非 const 函数。所以尽管需要一次转型,在 const 的 operator[] 中调用非 const 版本,可以安全地避免代码重复。下面是实例代码,读完后边的文字解说你会更明了。
class TextBlock {
public:
...
const char& 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[]
);
}
...
};
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-62399-5.html
#吴亦凡#
而且
等我们足够强大了再还击