看了bitset的源码,发现要重载下标运算符[]内容还挺多的,作右值时相对简单,只用来测试。作左值时就比较麻烦,因为要修改它的值。
1、作右值
举个例子:
const bitset<10> b;
bool tag;
tag = b.test(2);
tag = b[2];
上面第三句和第四句效果一样,都是测试b的下标为2的位是否为1。
当bitset为const时,operator[]执行的是:
bool operator[](size_t _Pos) const
{ // subscript nonmutable sequence
return (test(_Pos));
}
可以看到,内部还是调用了test。
2、作左值
举个例子:
bitset<10> b;
b.set(2);
b[2] = 1; // 或b.operator[](2) = 1; // 或(b.operator[](2)).operator=(1);
上面的第二句和第三句效果一样,都是将b的下标为2的位设置为1,其实执行第三句时内部还是要调用set()的。
下面详细介绍:
#include <iostream>
#include <bitset>
using namespace std;
int main(int argc, char **argv)
{
bitset<10> b;
// 第1步
bitset<10>::reference r = b.operator[](2);
// 函数名是operator[],实参是2,返回reference对象
// 第2步
r.operator=(1);
// 这里r._Pbitset与&b相等(原理就是r用_Pbitset记住了b的地址),故改变了*_Pbitset也就改变了b
// r无任何改变
// 最后结果
// r._Pbitset:[bitset] [10](0,0,1,0,0,0,0,0,0,0) 类型:std::bitset<10> *
// b: [10](0,0,1,0,0,0,0,0,0,0) 类型:std::bitset<10>
// 两者是一致的
return 0;
}
关于bitset类的定义,下面是个简化版:
// bitset类的简化版
// 为了与库bitset区别,这里首字母大写
class Bitset
{
public:
class Reference
{
friend class Bitset; // 为了Reference外Bitset内的operator[]能访问Reference构造函数(private)
public:
Reference& operator=(bool _Val) // 第2步,还是要调用set
{
_PBitset->set(_Mypos, _Val); // r没变,但(*_PBitset)即b改变了
return (*this);
}
private:
Bitset *_PBitset; // Key
size_t _Mypos;
Reference(Bitset& _Bitset, size_t _Pos) : _PBitset(&_Bitset), _Mypos(_Pos)
{
// 构造函数
}
};
Reference operator[](size_t _Pos) // 第1步
{
return (Reference(*this, _Pos));
// 这个地方用法很怪!直接调用构造函数,创建一个无名的临时对象
}
Bitset& set(size_t _Pos, bool _Val = true)
{
// 略
}
};
下面摘录自《C++ Primer》(李师贤译)P94:
下标操作返回左值,因此可将下标操作作为赋值操作的左操作数。对下标操作的结果赋值是赋一个新值到相应的元素。
但我认为这是有前提的!如第一种情况,读const bitset时调用的operator[]返回的就是bool类型,而非reference类型。
关于bitset的源码,可以在VC\include\bitset中找到。
最后一个问题:
bitset<10> b;
bool tag;
tag = b[2];
这个测试又跟第一种不同了,其实这种情况比const那种测试常见地多,下次再介绍了。