看了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 sequencereturn (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;// Keysize_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那種測試常見地多,下次再介紹了。