Я пытаюсь создать класс BoolArray, который представляет массив логических значений, но вместо сохранения 1 логического значения на переменную bool. он использует переменную 1 char для представления 8 логических значений, используя биты, и экономит память. Я хочу сделать его удобным, как обычный массив, используя operator [].
Я могу использовать arr [5] и вернуть значение bool для пятого бита. моя проблема в назначении немного. Я не могу сделать ссылку на один бит, поэтому мне нужно сделать функцию, которая выполняет эту задачу.
У меня вопрос, возможно ли управлять назначением стиля массива, используя перегрузку операторов. Моим решением было использовать другой класс (MyBoolean) и вернуть его как ссылку на оператор BoolArray []. MyBoolean перегружает operator = и изменяет биты BoolArray. Есть ли более простой способ, который перегружает вид оператора [] = или что-то в этом роде?
#include <iostream>
#include <tgmath.h>
using namespace std;string int_to_binary_string(int number)
{
if ( number == 0 ) return "0";
if ( number == 1 ) return "1";
if ( number % 2 == 0 )
return int_to_binary_string(number / 2) + "0";
else
return int_to_binary_string(number / 2) + "1";
}class MyBoolean;
class BoolArray {
private:
unsigned char* arr;
int size;void setBit(int bit_number,bool value);
public:
explicit BoolArray(int size);
~BoolArray();
MyBoolean operator[](unsigned int index);
int getSize() const;
friend class MyBoolean;
};// ***************************** MyBoolean *********************************
class MyBoolean {
private:
bool value;
int bit_number;
BoolArray* bool_array;
public:
// --- Constructor ---
MyBoolean(bool value,int bit_number,BoolArray* bool_array) :
value(value),bit_number(bit_number),bool_array(bool_array)
{}// --- cast ---
operator bool() const{
return value;
}
MyBoolean& operator=(bool new_value) {
value = new_value;
bool_array->setBit(bit_number,new_value);
}
};// ***************************** BoolArray *****************************
void BoolArray::setBit(int bit_number,bool value) {
int index = floor((double)bit_number/8);
bit_number -= index*8;
cout << "trying to set " << bit_number << " to " << value << endl;
if(value==true) {
int binary_num = pow(2,bit_number);
cout << "arr[index]: " << int_to_binary_string(arr[index]) << " - binary_num: " << int_to_binary_string(binary_num);
arr[index] = arr[index] | binary_num;
cout << " - after: " << int_to_binary_string(arr[index]) << endl;
}
else {
int binary_num = 0 | 255;
int binary_num_2 = pow(2,bit_number);
binary_num = binary_num^binary_num_2;
arr[index] = arr[index] & binary_num;
}
}// --- Constructor ---
BoolArray::BoolArray(int size) :
size(size)
{
size = ceil((double)size/8);
arr = new unsigned char[size];
}// --- Destructor ---
BoolArray::~BoolArray() {
delete[] arr;
}// --- operator[] ---
MyBoolean BoolArray::operator[](unsigned int index) {
if(index>size-1)
throw "error";
int arr_index = floor((double)index/8);
int bit_number = index - arr_index*8;
unsigned int binary_num = pow(2,bit_number);
int value= false;
if((arr[arr_index] & binary_num)>0)
value = true;
MyBoolean my_bool(value,index,this);
return my_bool;
}// --- size ---
int BoolArray::getSize() const {
return size;
}ostream& operator<<(ostream& os, MyBoolean b) {
os << (bool) b;
return os;
}
ostream& operator<<(ostream& os,BoolArray& arr) {
for(int i=0;i<arr.getSize();i++)
os << arr[i] << "->";
return os;
}int main() {
BoolArray arr(12);
arr[0] = true;
arr[1] = false;
arr[2] = true;
arr[3] = false;
arr[4] = true;
arr[5] = false;
arr[6] = true;
arr[7] = false;
arr[8] = true;
arr[9] = false;
arr[10] = true;
arr[11] = false;
cout << arr;
return 0;
}
У вас уже есть в основном лучшее решение: создать прокси-класс, который может быть назначен из bool, но внутренне присваивает только 1 бит и неявно преобразуется в bool
, BoolArray
вернул бы этот прокси-класс из operator[]
,
На самом деле, это то, что vector<bool>
делает с vector<bool>::reference
. Как сказали комментаторы, std::vector
специализируется на bool
делать именно то, что вы пишете. Так что, если это не только для обучения, то, что вы пишете, бесполезно / излишне.
Как предлагают вам комментаторы, используйте std::bitset
. Не изобретать велосипед.
Но если вы хотите выполнить упражнение и реализовать набор битов, ответ таков: НЕТ.
На самом деле, реализация std::bitset
делает именно то, что вы делаете: Использование прокси-класса, который хранит значение и позицию бита.
Пожалуйста, проверьте строки 00760 (Объявление класса прокси) и 01138 (Объявление и реализация неконстантного оператора []).
Использование прокси-объекта, как вы делаете, в принципе правильно. НО: вы никогда не должны использовать операции с плавающей запятой для целочисленной арифметики (они неточны, а иногда имеют небольшую точность):
// Don't do this:
int index = floor((double)bit_number/8);
// But this:
int index = bitnumber/8;
Целочисленное деление всегда будет округлять до нуля, используя floor(x)
не нужен
// Don't do this:
int binary_num = pow(2,bit_number);
// But this:
int binary_num = 1 << bit_number;
В дополнение к возможному неправильному результату после округления до целых чисел, pow(a,b)
намного медленнее, чем использование оператора сдвига битов.