Effective c++笔记:03 尽可能使用const

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

对于‘bitwise-constness‘的问题,mutable是一个解决方法,但是不能解决所有。

试想,假设TextBlock类的内部operator[]不仅仅返回一个reference指向某个字符,也执行边界检验,志记访问信息,甚至可能进行数据完整性检验。

把所有这些功能同时放入const和non-const operator[]之中,将会导致长度颇为可议的隐式inline函数。

class TextBlock {
    public:
    ...

    char &operator[](std::size_t position) {
        //边界检查
        //志记数据访问
        //检验数据完整性
        return text[position];
    }
    const char &operator[]() const {
        //边界检查
        //志记数据访问
        //检验数据完整性
        return text[position];
    }

    private:
        std::string text;
};

分析:
这样写无疑会导致大量代码重复以及编译,维护,膨胀等因素等等问题。
当然,可以将边界检验… 等代码用另一个成员函数(往往是private)存放起来,并让两个operator[]调用它。但是这样做还是重复了代码。


有没有更好的方法呢?

我们真正该做的应该是实现operator[]的机能一次,并且能够使用它两次!
也就是说,想办法让其中一个调用另外一个。这促使我们将使用常量性转除

就一般守则而言,使用转型(casting)是一个糟糕的做法。
本例中 const operator[] 完全做到了 non-const operator[] 所该做的一切,唯一的不同是,它的返回值多了一个const修饰。这种情况下,如果将返回值的const转除是安全的,因为无论谁调用 non-const operator[] 都一定首先需要有个 non-const 对象,否则就无法调用non-const函数。
所以:
令 non-const operator[] 调用其 const 兄弟是一个避免代码重复的安全做法,即使过程中需要一个转型(casting)操作。


代码如下:

//effective 03
#include <iostream>


using namespace std;

class TextBlock {
    public:
        TextBlock() {}
        TextBlock(std::string t) : text(t) {}
        ~TextBlock() {}

        TextBlock(const std::string &t) {
            text = t; 
        }

        TextBlock(const std::string &&t) {
            std::string temp = std::move(t);
            this->text = temp;
        }

        //const和非const版本
        //const版本是必须的 基础,非const可以通过调用const实现
        const char &operator[](std::size_t position) const {
            return text[position];
        } 

        char &operator[](std::size_t position) {        
            return  const_cast<char &>(
                static_cast<const TextBlock &>(*this)[position]); 

        }
    private:
        std::string text;
};

代码有两个转型操作。
我们打算让 non-const 调用其 const 兄弟,但是 non-const operator[] 若知识单纯地调用 operator[] ,就会导致递归调用自己。
所以,我们必须明确指明调用的是 const operator[] ,但是c++缺乏直接的语法。
因此,这里将 (*this)指针从它的原始类型 TextBlock & 转换为 const TextBlock &
第一次转型:为 *this 指针添加 const 修饰,使得调用 [] 时候一定是调用 const operator[]
第二次转型:从 const operator[] 的返回值中移除 const

添加 const 的第一次转换强制进行了一次安全转型(将 non-const 对象转化为 const 对象),所以我们使用 static_cast
移除 const 的那个操作只能使用 const_cast 完成。

虽然这样写,语法上第一次看有点点不懂,但是我们却能够避免代码重复,使用 const operator[] 实现了 non-const operator[] 版本。

更值得我们了解的是:
令 const 版本调用 non-const 版本以避免重复,这并不是我们该做的事情!
Rember:
const成员函数承诺绝不会改变其对象的逻辑状态,non-const成员函数却没有这样的承诺。
如果在 const 成员函数内调用了 non-const 函数,就是冒了这样的风险;曾经承诺不改变的对象可能被改变了!
这就是为什么? const 成员函数调用 non-const 成员函数是错误的行为。

所以本例使用 static_cast 作用于 *this 的原因,这里并不存在 const 相关危险。


请记住:

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

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

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

补充:

bitwise constness 和 logical constness

bitwise const阵营的人相信,成员函数只有在不更改对象之任何成员变量时才能说是 const ,也就是它不更改任何一个bit。这种观点的好处是很容易侦测违反点:编译器只需要寻找成员变量的赋值动作即可。
bitwise constness 正是c++对于常量性的定义。
因此 const 成员函数不可以更改对象内任何 non-const 成员变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值