面向物件程式設計第一次實驗課——位運算封裝
題目的大意是用一個類封裝位運算,並通過位運算實現四則運算。我一下子就想起了bitset,但是bitset並不支援四則運算。後來想想也許叫大整數類比較合適吧。
當然還是有很多問題的,有些問題是寫完了才發現的,當時發著高燒,一邊寫一邊debug,好不容易趕到deadline前,交過之後也沒有改的動力了……
首先是該用友元實現的二元關係的運算子全寫在類內了,寫之前應該看看書的。其次是沒有實現下標運算子的過載,這個要用到設計模式中的代理模式,同樣是沒來得及寫,這裡有篇blog裡面實現了:
http://blog.csdn.net/fastsort/article/details/8922923
一些其他問題寫在了實驗報告中。
bit.h
#pragma once
#include <string>
#include <cstring>
#include <cmath>
#define BLOCK (len_ / (8 * sizeof(size_t)) + (len_ % (sizeof(size_t) * 8)? 1: 0))
#define BLOCKBIT (8 * sizeof(size_t))
using namespace std;
template <size_t len_> //len_ is the number of bit(s)
class myBitset {
friend ostream& operator<< (ostream &out, const myBitset<len_>& bs)
{
// stored reversely, so output reversely
for (size_t i = 0; i < len_; i ++) {
if (bs.isTrue(len_ - i - 1)) out << "1";
else out << "0";
// printf("%d ",i);
}
return out;
}
public:
myBitset() : block_(BLOCK)
{
num_ = new size_t[block_];
memset(num_, 0, block_ * sizeof(size_t));
// printf("%d %d %d\n", block_, sizeof(size_t), block_ * sizeof(size_t));
// for (int i = 0; i < block_; i ++) num_[i] = 0;
// cout << *this << endl;
}
myBitset(const myBitset& bs);
//invert signed number to myBitset, and avoid ambiguous calling for overloaded functions
myBitset(signed int num);
myBitset(unsigned int num);
myBitset(signed long);
myBitset(unsigned long);
// myBitset(signed long long);
// myBitset(unsigned long long);
myBitset(signed __int64 num);
myBitset(unsigned __int64 num);
myBitset(const string& s);
~myBitset();
myBitset& operator= (const myBitset& bs);
myBitset operator& (const myBitset& bs) const;
myBitset operator| (const myBitset& bs) const;
myBitset operator~ (void) const;
myBitset operator^ (const myBitset& bs) const;
// BOTH TWO BELOW ARE LOGICAL SHIFT! BE CAREFUL !
myBitset operator<< (size_t shift) const;
myBitset operator>> (size_t shift) const;
myBitset& operator&= (const myBitset& bs);
myBitset& operator|= (const myBitset& bs);
myBitset& operator^= (const myBitset& bs);
myBitset& operator<<= (size_t shift);
myBitset& operator>>= (size_t shift);
myBitset& operator++ (void);
myBitset& operator-- (void);
myBitset operator++ (int dummy);
myBitset operator-- (int dummy);
// in operator+= we need local variables of myBitset, so argument is not reference
myBitset& operator+= (myBitset bs);
myBitset& operator-= (const myBitset& bs);
myBitset operator+ (const myBitset& bs) const;
myBitset operator- (const myBitset& bs) const;
myBitset operator+ (void) const;
myBitset operator- (void) const;
myBitset operator* (const myBitset& bs) const;
myBitset operator/ (const myBitset& bs) const;
// myBitset operator% (const myBitset& bs) const;
myBitset& operator*= (myBitset bs);
myBitset& operator/= (myBitset bs);
bool operator> (const myBitset& bs) const;
bool operator>= (const myBitset& bs) const;
bool operator< (const myBitset& bs) const;
bool operator<= (const myBitset& bs) const;
bool operator== (const myBitset& bs) const;
bool operator!= (const myBitset& bs) const;
explicit operator bool(void) const;
void flip();// flip all bits
void set(size_t index);
void reset(size_t index);
bool isTrue(size_t index) const;
size_t getBlock(void) { return block_;}
size_t getLen(void) { return len_;}
private:
size_t* num_; //pointer to where the bits stored
const size_t block_; //the size of the array
};
template <size_t len_> myBitset<len_>::myBitset(const myBitset<len_>& bs) :
block_(bs.block_)
{
num_ = new size_t[block_];
for (size_t i = 0; i < bs.block_; i ++)
num_[i] = bs.num_[i];
}
// lower bit is stored in the smaller index
template <size_t len_> myBitset<len_>::myBitset(unsigned __int64 num) : myBitset()
{
size_t p = 0;
// printf("%llu\n",num);
while (num && p < len_) {
if (num & 1) {
set(p);
// printf("%d\n",p);
}
++ p;
num >>= 1;
}
// size_t is an unsigned type !!
}
//template <size_t len_> myBitset<len_>::myBitset(unsigned long long num) :
// myBitset(unsigned __int64(num)) {}
template <size_t len_> myBitset<len_>::myBitset(unsigned long num) :
myBitset(static_cast<unsigned __int64>(num)) {}
template <size_t len_> myBitset<len_>::myBitset(unsigned int num) :
myBitset(static_cast<unsigned __int64>(num)) {}
template <size_t len_> myBitset<len_>::myBitset(signed __int64 num) :
myBitset(static_cast<unsigned __int64>(abs(num)))
{
if (num < 0) {
flip();
++ (*this);
}
}
//template <size_t len_> myBitset<len_>::myBitset(signed long long num) :
// myBitset(signed __int64(num)) {}
template <size_t len_> myBitset<len_>::myBitset(signed long num) :
myBitset(static_cast<signed __int64>(num)) {}
template <size_t len_> myBitset<len_>::myBitset(signed int num) :
myBitset(static_cast<signed __int64>(num)) {}
template <size_t len_> myBitset<len_>::myBitset(const string& s) : myBitset()
{
for (size_t i = 0; i < s.size(); i ++) {
if (s[i] != '0') {
set(s.size() - i - 1);
}
}
}
template <size_t len_> myBitset<len_>::~myBitset()
{
delete []num_;
}
template <size_t len_> inline void myBitset<len_>::set(size_t index)
{
// 1不加強制型別轉換為什麼會出現迴圈左移……
num_[index / BLOCKBIT] |= (size_t(1) << (index % BLOCKBIT));
// printf("%d %d %d\n",index, index / BLOCKBIT, index % BLOCKBIT);
return ;
}
template <size_t len_> inline void myBitset<len_>::reset(size_t index)
{
num_[index / BLOCKBIT] &= ~(size_t(1) << (index % BLOCKBIT));
return ;
}
template <size_t len_> inline bool myBitset<len_>::isTrue(size_t index) const
{
// if (num_[index / BLOCKBIT] & (size_t(1) << (index % BLOCKBIT))) printf(" %d %d %d\n",index, index / BLOCKBIT,index %BLOCKBIT);
// printf("%llu\n",1 << (index % BLOCKBIT));
return num_[index / BLOCKBIT] & (size_t(1) << (index % BLOCKBIT));
}
template <size_t len_> inline void myBitset<len_>::flip(void)
{
for (size_t i = 0; i < block_; i ++) {
num_[i] = ~num_[i];
}
return ;
}
template <size_t len_> myBitset<len_>& myBitset<len_>::operator= (const myBitset& bs)
{
if (this != &bs) {
for (size_t i = 0; i < block_; i ++)
num_[i] = bs.num_[i];
}
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator&(const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs &= bs;
return tbs;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator|(const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs |= bs;
return tbs;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator~(void) const
{
myBitset<len_> tbs(*this);
tbs.flip();
return tbs;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator^(const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs ^= bs;
return tbs;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator<<(size_t shift) const
{
myBitset<len_> tbs(*this);
tbs <<= shift;
return tbs;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator>>(size_t shift) const
{
myBitset<len_> tbs(*this);
tbs >>= shift;
return tbs;
}
template<size_t len_> myBitset<len_>& myBitset<len_>::operator&= (const myBitset& bs)
{
for (size_t i = 0; i < block_; i ++) {
num_[i] &= bs.num_[i];
}
return *this;
}
template<size_t len_> myBitset<len_>& myBitset<len_>::operator|= (const myBitset& bs)
{
for (size_t i = 0; i < block_; i ++) {
num_[i] |= bs.num_[i];
}
return *this;
}
template<size_t len_> myBitset<len_>& myBitset<len_>::operator^= (const myBitset& bs)
{
for (size_t i = 0; i < block_; i ++) {
num_[i] ^= bs.num_[i];
}
return *this;
}
template<size_t len_> myBitset<len_>& myBitset<len_>::operator<<= (size_t shift)
{
if (shift == 0) return *this;
if (shift >= len_) {
memset(num_, 0, block_ * sizeof(size_t));
return *this;
}
size_t blockShift = shift / BLOCKBIT; // the shift of how many units of array
size_t innerShift = shift % BLOCKBIT; // the shift in the unit of array
for (size_t i = 0; i < block_; i ++) {
size_t opid = block_ - 1 - i;
if (opid < blockShift) {
num_[opid] = 0;
} else {
if (opid - blockShift > 0)
num_[opid]=(num_[opid-blockShift]<<innerShift)|(num_[opid-blockShift-1]>>(BLOCKBIT-innerShift));
else
num_[opid] = num_[opid - blockShift] << innerShift;
}
}
return *this;
}
template<size_t len_> myBitset<len_>& myBitset<len_>::operator>>= (size_t shift)
{
// printf("%llu\n",num_[0]);
if (shift == 0) return *this;
if (shift >= len_) {
memset(num_, 0, block_ * sizeof(size_t));
return *this;
}
size_t blockShift = shift / BLOCKBIT; // the shift of how many units of array
size_t innerShift = shift % BLOCKBIT; // the shift in the unit of array
for (size_t i = 0; i < block_; i ++) {
if (i > block_ - 1 - blockShift) {
num_[i] = 0;
} else {
if (i + blockShift + 1 < block_)
num_[i]=(num_[i+blockShift]>>innerShift)|(num_[i+blockShift+1]<<(BLOCKBIT-innerShift));
else
num_[i] = num_[i + blockShift] >> innerShift;
}
}
// printf("%llu\n",tbs.num_[0]);
return *this;
}
template <size_t len_> inline myBitset<len_>& myBitset<len_>::operator++ (void)
{
(*this) += 1;
return *this;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator++ (int dummy)
{
myBitset<len_> tbs = (*this);
++ (*this);
return tbs;
}
template <size_t len_> inline myBitset<len_>& myBitset<len_>::operator-- (void)
{
(*this) -= 1;
return *this;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator-- (int dummy)
{
myBitset<len_> tbs = (*this);
-- (*this);
return tbs;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator+ (const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs += bs;
return tbs;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator- (const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs += -bs;
return tbs;
}
template <size_t len_> inline myBitset<len_>& myBitset<len_>::operator-= (const myBitset& bs)
{
*this += -bs;
return *this;
}
template <size_t len_> inline myBitset<len_>& myBitset<len_>::operator+= (myBitset bs)
{
myBitset<len_> tbs;
while ((bs)) {
tbs = (*this) ^ bs;
bs = (*this & bs) << 1;
*this = tbs;
}
return *this;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator+ (void) const
{
return *this;
}
template <size_t len_> inline myBitset<len_> myBitset<len_>::operator- (void) const
{
myBitset<len_> tbs(*this);
return ~(tbs) + 1;
}
template<size_t len_> myBitset<len_>::operator bool(void) const
{
for (size_t i = 0; i < len_ ; i ++) {
if (isTrue(i))
return true;
}
return false;
}
template <size_t len_> myBitset<len_>& myBitset<len_>::operator*= (myBitset bs)
{
if (!bs || !*this) {
*this = 0;
return *this;
}
int flag = 0;
myBitset<len_> tbs(*this);
*this = 0;
if (isTrue(len_ - 1)) {
flag = ~flag;
tbs = -tbs;
}
if (bs.isTrue(len_ - 1)) {
flag = ~flag;
bs = -bs;
}
while (bs) {
if (bs & 1)
*this += tbs;
tbs <<= 1;
bs >>= 1;
}
if (flag) {
*this = -(*this);
}
return *this;
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator* (const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs *= bs;
return tbs;
}
template <size_t len_> myBitset<len_>& myBitset<len_>::operator/= (myBitset bs)
{
// cout << *this << " " << bs << endl;
if (bs) {
int flag = 0;
myBitset<len_> tbs(*this);
*this = 0;
if (tbs.isTrue(len_ - 1)) {
flag = ~flag;
tbs = -tbs;
}
if (bs.isTrue(len_ - 1)) {
flag = ~flag;
bs = -bs;
}
// cout << tbs << " " << bs << endl;
size_t highbit = 0;
for (size_t i = len_ - 2; i > 0; i --) {
if (tbs.isTrue(i)) {
highbit = i;
break;
}
}
for (size_t i = 0; i <= highbit; i ++) {
size_t op = highbit - i;
// avoid overflow!!!
if ((tbs >> op) >= bs) {
tbs -= (bs << op);
*this += (myBitset<len_>(1) << op);
}
// cout << op << " " << tbs << " " << bs << " " << *this << endl;
}
if (flag) {
*this = -(*this);
}
return *this;
} else {
cout << "divisor cannot be 0 !" << endl;
return *this;
}
}
template <size_t len_> myBitset<len_> myBitset<len_>::operator/ (const myBitset& bs) const
{
myBitset<len_> tbs(*this);
tbs /= bs;
return tbs;
}
template <size_t len_> bool myBitset<len_>::operator>= (const myBitset& bs) const
{
return (*this > bs || *this == bs);
}
template <size_t len_> bool myBitset<len_>::operator> (const myBitset& bs) const
{
if (!isTrue(len_ - 1) && isTrue(len_ - 1)) {
return true;
}
if (isTrue(len_ - 1) && !isTrue(len_ - 1)) {
return false;
}
for (size_t i = 0; i < block_; i ++) {
size_t op = block_ - i - 1;
if (num_[op] > bs.num_[op]) {
return true;
}
if (num_[op] < bs.num_[op]) {
return false;
}
}
return false;
}
template <size_t len_> bool myBitset<len_>::operator== (const myBitset& bs) const
{
if (*this ^ bs) {
return false;
} else {
return true;
}
}
template <size_t len_> inline bool myBitset<len_>::operator< (const myBitset& bs) const
{
return !(*this >= bs);
}
template <size_t len_> inline bool myBitset<len_>::operator<= (const myBitset& bs) const
{
return !(*this > bs);
}
template <size_t len_> inline bool myBitset<len_>::operator!= (const myBitset& bs) const
{
return !(*this == bs);
}
main.cpp
裡面主要是測試
#include <iostream>
#include <cmath>
#include "bit.h"
#include <bitset>
using namespace std;
int main(int argc, char** argv)
{
cout << (-11111 >> 30) << endl;
cout << size_t(-1) << endl;
cout << "test for set, reset and flip" << endl;
myBitset<32> bt;
bt.set(0);
cout << bt << endl;
bt.reset(0);
cout << bt << endl;
bt.set(31);
cout << bt << endl;
bt.flip();
cout << bt << endl;
cout << endl << "test for constructor" << endl;
string s = "100010";
myBitset<32> bt1;
cout << bt1 << endl;
myBitset<33> bt2(s);
cout << bt2 << endl;
myBitset<33> bt31(64);
cout << bt31 << endl;
myBitset<65> bt32(static_cast<unsigned long long>((size_t(1) << 63) + ((size_t(1) << 63) - 1)));
cout << bt32 << endl;
myBitset<33> bt4(bt31);
cout << bt4 << endl;
cout << endl << "test for <<, >> and =" << endl;
myBitset<100> bt5(size_t(pow(2,31))+15);
cout << bt5 << endl;
cout << (bt5 << 4) << endl;
cout << (bt5 >> 4) << endl;
cout << (size_t(1) << 33) << endl;
myBitset<100> bt6("100000011111111111000010101");
cout << bt6 << endl;
bt6 = bt5;
cout << bt6 << endl;
myBitset<129> bt7 = string("10110011101111011111010101");
cout << bt7 << endl;
cout << (bt7 >> 7) << endl;
cout << (bt7 << 7) << endl;
cout << (bt7 << 65) << endl;
cout << (bt7 >> 65) << endl;
cout << endl << "test for &, |, ~ and ^" << endl;
myBitset<70> bt8("1011011101111011111011111101111111011111111011111111101111111111011110");
cout << bt8 << endl;
myBitset<70> bt9(~bt8);
cout << bt9 << endl;
cout << (bt8 | bt9) << endl;
cout << (bt8 & bt9) << endl;
cout << (bt8 ^ bt9) << endl;
cout << (bt8 ^ bt9 ^ bt8) << endl;
cout << endl << "test for &=, |= and ^=" << endl;
cout << bt8 << endl;
bt8 &= bt9;
cout << bt8 << endl;
bt8 |= bt9;
cout << bt8 << endl;
bt8 ^= ~bt9 ^ 1;
cout << bt8 << endl;
cout << endl << "test for <<= and >>=" << endl;
myBitset<70> bt10("1011011101111011111011111101111111011111111011111111101111111111011111");
cout << bt10 << endl;
cout << (bt10 << 65) << endl;
bt10 <<= 65;
cout << bt10 << endl;
bt10 = string("1011011101111011111011111101111111011111111011111111101111111111011111");
cout << (bt10 >> 65) << endl;
bt10 >>= 65;
cout << bt10 << endl;
cout << endl << "test for + and -" << endl;
bt9 = string("1011011101111011111011111101111111011111111011111111101111111111011111");
bt10 = ~bt9;
cout << bt9 << endl;
cout << bt10 << endl;
cout << (-bt9) << endl;
cout << (-bt10) << endl;
cout << (bt9 + bt10) << endl;
cout << (bt9 - (bt10>>3)) << endl;
bt9 = -1;
bt10 = 64;
cout << (bt9 + bt10) << endl;
cout << (bt9 - bt10) << endl;
cout << endl << "test for ++, -- , += and -=" << endl;
bt9 = string("1011011101111011111011111101111111011111111011111111101111111111011111");
bt10 = ~bt9;
cout << (bt9 ++) << endl;
cout << bt9 << endl;
cout << (bt10 --) << endl;
cout << bt10 << endl;
cout << (++ bt9) << endl;
cout << bt9 << endl;
cout << (-- bt10) << endl;
cout << bt10 << endl;
bt10 += 1;
cout << bt10 << endl;
bt10 -= 3;
cout << bt10 << endl;
cout << endl << "test for *, *=, /, /=" << endl;
bt9 = -13;
bt10 = 3;
bt9 *= bt10;
cout << bt9 << endl;
cout << (bt9 * bt10) << endl;
bt9 *= -3;
bt10 *= 100;
cout << bt9 << endl;
cout << bt10 << endl;
cout << endl << "test for /, /=" << endl;
bt9 = 10;
bt10 = 3;
cout << (bt9 >= bt10) << endl;
cout << (bt9 >> 3) << endl;
cout << ((bt9 >> 3) >= bt10) << endl;
cout << (bt9 << 0) << endl;
cout << (myBitset<70>(1) << 0) << endl;
bt9 /= bt10;
cout << bt9 << endl;
bt9 = -10;
bt10 = 3;
cout << (bt9 / bt10) << endl;
cout << (bt10 / bt9) << endl;
return 0;
}
附:實驗報告
第一次實驗報告
一、 題目分析
位運算的封裝:
第一次看到這個題目,我想到了stl中的bitset,bitset實現了對bit型別陣列的封裝,同時支援六種位運算,我的目的就是實現類似於bitset的類模版。
六種位運算& | ~ ^ << >> 支援基礎資料型別,但是基礎資料型別的大小是固定的,不能支援bit數高於8 * sizeof(size_t)(最大一般是64bit)的要求,而且不能支援任意位數的bit型別陣列,這樣顯然不能滿足我們的要求。
因此,我決定使用size_t型別的陣列,通過基礎型別的位運算實現對每一個size_t內的位的操作,從而實現對抽象的“位型別”的操作。
除了最基礎的建構函式、解構函式、拷貝運算子,實現了六種位運算,還實現了布林型別的型別轉換,邏輯運算,和+-*/四則運算和自增自減運算以及流插入操作符過載。
100!的計算:
首先想到的是高精度乘法,通過陣列儲存大數的每一位,模擬豎式乘法,從而得解。
二、 流程分析(感覺太複雜了畫圖有些困難,所以通過文字描述)
這裡介紹位運算封裝的流程,大數階乘比較簡單。
1. 建構函式:
共9個,最基礎的是預設建構函式,在其中完成相關變數初始化和記憶體空間的申請。
之後是拷貝建構函式,myBitset(unsigned __int64 num); myBitset(const string& s); 它們首先使用預設建構函式進行委託構造,之後再實現自己特定的構造。
在之後是以其他各種無符號或有符號整數做引數的建構函式,它們使用myBitset(unsigned __int64 num);進行委託構造,從而完成功能。
2.基礎功能的實現
共4個,分別是
void flip();
void set(size_t index);
void reset(size_t index);
bool isTrue(size_t index) const;
flip實現按位取反,set實現對下標是index的置1,reset是實現對下標是index的置0,isTrue判斷下標為index的位是否是1,接下來的許多函式都是需要直接或者間接呼叫這些函式的。
2. 位運算運算子以及=的過載
myBitset& operator= (const myBitset& bs);
myBitset operator& (const myBitset& bs) const;
myBitset operator| (const myBitset& bs) const;
myBitset operator~ (void) const;
myBitset operator^ (const myBitset& bs) const;
myBitset operator<< (size_t shift) const;
myBitset operator>> (size_t shift) const;
myBitset& operator&= (const myBitset& bs);
myBitset& operator|= (const myBitset& bs);
myBitset& operator^= (const myBitset& bs);
myBitset& operator<<= (size_t shift);
myBitset& operator>>= (size_t shift);
首先實現的是&= |= 等函式,之後& |等運算子通過呼叫&= |= 等實現功能。
3. 四則運算與自增自減
myBitset& operator++ (void);
myBitset& operator– (void);
myBitset operator++ (int dummy);
myBitset operator– (int dummy);
myBitset& operator+= (myBitset bs);
myBitset& operator-= (const myBitset& bs);
myBitset operator+ (const myBitset& bs) const;
myBitset operator- (const myBitset& bs) const;
myBitset operator+ (void) const;
myBitset operator- (void) const;
myBitset operator* (const myBitset& bs) const;
myBitset operator/ (const myBitset& bs) const;
myBitset& operator*= (myBitset bs);
myBitset& operator/= (myBitset bs);
同樣,首先實現的是+= -=等,對應的雙目運算子則呼叫前者,單目-呼叫~運算子。
前置自增自減呼叫+= -=,而後置自增自減呼叫前置自增自減。
4. 邏輯運算子與bool型別轉換
bool operator> (const myBitset& bs) const;
bool operator>= (const myBitset& bs) const;
bool operator< (const myBitset& bs) const;
bool operator<= (const myBitset& bs) const;
bool operator== (const myBitset& bs) const;
bool operator!= (const myBitset& bs) const;
explicit operator bool(void) const;
bool型別轉換函式呼叫isTrue函式。
實現的是>和==,其他邏輯運算子直接或間接呼叫這兩個函式。
三、程式難點以及遇到的主要bug
1.建構函式
為了支援四則運算,必須提供引數無符號整型和有符號整型的建構函式,開始我只定義了unsigned __int64和 signed __int64為引數的建構函式,然而這時就會遇到二義呼叫的問題。
為了避免二義呼叫,我為常見的整型型別分別定義了建構函式。
2.移位運算
因為儲存位的是陣列,故實現移位操作時會遇到困難,通過尋找規律可以解決這一問題。
此外還遇到了如下問題。
一開始我並沒有對1進行強制型別轉換,轉換成myBitset型別,按道理,1移位超過int位長時,這樣會使1移位後的結果變成0(邏輯移位),但是,這裡實際上竟然是迴圈移位。
而單單對1進行左移位,得到的結果是邏輯移位的結果。
目前還是沒有弄明白是為什麼。
因為首先實現的是<<=和>>= ,<< >>是通過呼叫<<= >>= 實現的,移位的時候可能會出現運算結果覆蓋未進行運算資料的情況,所以要注意運算的順序,>>要先從低位開始算,<<要先從高位開始算。
還遇到了移位0時出現的錯誤,需要特判shift為0時的情況。(除法呼叫移位操作時發現)
3.bool型別轉換
一開始並沒有把operator bool 宣告為explicit,於是出現了雙目運算子呼叫時的二義呼叫(左運算元為myBitset物件而右運算元為基礎資料型別時),因為myBitset可以隱式的轉換為bool型別,c++中bool型別實質上就是int型別。
在查資料之前,我嘗試了在宣告中加入了explicit關鍵字,儘管在我的印象中它只能用在建構函式的宣告中,但是問題的確解決了,後來查資料發現,在c++11標準中,允許在型別轉換運算子前加入explicit的宣告,而對bool則更加特殊,在條件表示式中它允許隱式轉換而在其他情況中只允許顯式使用。
5. 不小心就會發生的間接遞迴
由於一些運算子要通過呼叫其他運算子實現,所以在頭腦不清晰的情況下極易發生
遞迴,而且這類錯誤比較難發現,程式中出現的最長間接遞迴鏈甚至可達10個以上的函式。
6. 乘法與除法
在設計乘法的演算法時我借鑑了快速冪演算法的思想,只不過當第二個乘數為奇數時ans變數做的運算由乘變成了加,只要呼叫加法就可以實現乘法了。
除法就是乘法的逆運算。
7. size_t型別
size_t型別是一種無符號整數型別,具體型別依賴於環境,但它是非負的,用size_t型別做迴圈變數時,由於它不可能小於0,於是下面的語句會出現死迴圈。
For (size_t I = len_ - 1; I >= 0; I ++)
故程式中所有迴圈儘量寫成正序的,需要反向的順序時,通過迴圈變數計算出實際運算的下標。
四、 優點與缺點
封裝位運算操作符
優點:
a) 實現了任意長度的位型別
b) 滿足了所有的要求
c) 儘量使用已定義的方法去定義其他方法
d) 對於多個方法(已實現的或是以後可能實現的)會使用的相同方法,將該方法定義為一個函式
e) 實現了四則運算,自增自減,過載了流插入操作符。
缺點:
a) 最重大的失誤:沒有將二元運算子用非成員函式實現。(3 + myBitset<10>(1)是非法的)
b) 沒有實現[]操作符。(代理模式)
c) 沒有用myBitset類實現階乘(主要是沒有轉換成整型的方法)
d) 沒有定義將myBitset轉換為整型的方法(大數進位制轉換)
e) 部分方法效率不高