Ошибка: assignment of member 'VectorOfInt::sts' in read-only object C++

Всем привет! Не могу понять, почему появляется ошибка, когда я пытаюсь установить переменную состояния в функции, которая получает некоторое значение массива в абстрактном типе данных - класс вектор.

Где начинается ошибка:

// Функция, получающая некоторый элемент массива
const int VectorOfInt::getValue(size_t index) const {
    if (index < size) {
        sts = OK; // error assignment of member 'VectorOfInt::sts' in read-only object
        return data[index];
    }
    else {
        sts = ERR_OUT; // error assignment of member 'VectorOfInt::sts' in read-only object
        cout << "Error: index went out of range\nCode: ERR_OUT";
    }
}

Мой код:

#include <iostream>
#include <stdexcept>
using namespace std;

class VectorOfInt {
    private:
        int *data;
        size_t size;
        enum status { OK, ERR_MEM, ERR_OUT };
        status sts;
    
    public:
        // Конструктор без параметров
        VectorOfInt();
        
        // Конструктор с одним параметром
        VectorOfInt(size_t);
        
        // Конструктор с двумя параметрами
        VectorOfInt(size_t, int);
        
        // Копирующий конструктор
        VectorOfInt(const VectorOfInt &);
        
        // Деструктор
        ~VectorOfInt();
        
        // Функция, присваивающая элементу массива значение
        void setValue(size_t, int);
        
        // Функция, получающая некоторый элемент массива
        const int getValue(size_t) const;
        
        // Функция печати
        ostream &operator << (const VectorOfInt &);
        
        // Функция сложения
        VectorOfInt operator+();
        
        // Функция умножения
        VectorOfInt operator*();
        
        // Функция вычитания
        VectorOfInt operator-();
        
        // Метод сравнения >
        bool operator>(const &);
        
        // Метод сравнения <
        bool operator<(const &);
        
        // Метод сравнения ==
        bool operator==(const &);
        
        // Функция, возвращающая размер созданного вектора
        size_t getSize() const;
};

// Конструктор без параметров
VectorOfInt::VectorOfInt() {
    size = 1;
    data = new int[size];
}

// Конструктор с одним параметром
VectorOfInt::VectorOfInt(size_t size) {
    this -> size = size;
    data = new int[size];
    for (size_t i = 0; i < size; i++)
        data[i] = i;
}

// Конструктор с двумя параметрами
VectorOfInt::VectorOfInt(size_t size, int value) {
    this -> size = size;
    data = new int[size];
    for (size_t i = 0; i < size; i++)
        data[i] = value;
}

// Копирующий конструктор
VectorOfInt::VectorOfInt(const VectorOfInt &other) {
    data = new int[size = other.size];
    for (size_t i = 0; i < size; i++)
        data[i] = other.data[i];
}

// Деструктор
VectorOfInt::~VectorOfInt() {
    delete[] data;
}

// Функция, присваивающая элементу массива значение
void VectorOfInt::setValue(size_t index, int value) {
    if (index < size) {
        sts = OK;
        data[index] = value;
        // return 0;
    }
    else {
        sts = ERR_OUT;
        cout << "Error: index went out of range\nCode: ERR_OUT";
        // return 0;
    }
}

// Функция, получающая некоторый элемент массива
const int VectorOfInt::getValue(size_t index) const {
    if (index < size) {
        sts = OK; // error assignment of member 'VectorOfInt::sts' in read-only object
        return data[index];
    }
    else {
        sts = ERR_OUT; // error assignment of member 'VectorOfInt::sts' in read-only object
        cout << "Error: index went out of range\nCode: ERR_OUT";
    }
}

// Функция печати
ostream &operator << (ostream &stream, const VectorOfInt &v) {
    stream << "[";
    for (size_t i = 0; i < v.getSize(); ++i) {
        stream << v.getValue(i);
        if (i < v.getSize() - 1)
            stream << ", ";
    }
    return stream << "]";
}

// Функция сложения
VectorOfInt operator+(VectorOfInt &vec1, VectorOfInt &vec2) {
    if (vec1.getSize() >= vec2.getSize()) {
        VectorOfInt result(vec1.getSize());
        for (int i = 0; i < vec1.getSize(); i++)
            result.setValue(i, vec1.getValue(i) + vec2.getValue(i));
        return result;
    }
    else {
        VectorOfInt result(vec2.getSize());
        for (int i = 0; i < vec2.getSize(); i++)
            result.setValue(i, vec1.getValue(i) + vec2.getValue(i));
        return result;
    }
}

// Функция умножения
VectorOfInt operator*(VectorOfInt &vec1, VectorOfInt &vec2) {
    if (vec1.getSize() > vec2.getSize()) {
        VectorOfInt result(vec1.getSize());
        for (int i = 0; i < vec1.getSize(); i++)
            result.setValue(i, vec1.getValue(i) * vec2.getValue(i));
        return result;
    }
    else {
        VectorOfInt result(vec2.getSize());
        for (int i = 0; i < vec2.getSize(); i++)
            result.setValue(i, vec1.getValue(i) * vec2.getValue(i));
        return result;
    }
}

// Функция вычитания
VectorOfInt operator-(VectorOfInt &vec1, VectorOfInt &vec2) {
    if (vec1.getSize() > vec2.getSize()) {
        VectorOfInt result(vec1.getSize());
        for (int i = 0; i < vec1.getSize(); i++)
            result.setValue(i, vec1.getValue(i) - vec2.getValue(i));
        return result;
    }
    else {
        VectorOfInt result(vec2.getSize());
        for (int i = 0; i < vec2.getSize(); i++)
            result.setValue(i, vec1.getValue(i) - vec2.getValue(i));
        return result;
    }
}

// Метод сравнения >
bool operator>(VectorOfInt &vec1, VectorOfInt &vec2) {
    return vec1.getSize() > vec2.getSize();
}

// Метод сравнения <
bool operator<(VectorOfInt &vec1, VectorOfInt &vec2) {
    return vec1.getSize() < vec2.getSize();
}

// Метод сравнения ==
bool operator==(VectorOfInt &vec1, VectorOfInt &vec2) {
    return vec1.getSize() == vec2.getSize();
}

// Функция, возвращающая размер созданного вектора
size_t VectorOfInt::getSize() const {
    return size;
}

int main() {
    VectorOfInt v1(10);
    cout << "VectorOfInt v1(10) -> " << v1 << endl << endl;
    
    v1.setValue(3, 123);
    cout << "v1.setValue(3, 123) -> " << v1 << endl << endl;
    
    cout << "v1.getSize() -> ";
    cout << v1.getSize() << endl << endl;
    
    VectorOfInt v2(10, 7);
    cout << "VectorOfInt v2(10) -> " << v2 << endl << endl;
    
    cout << "-------------------------------";
    cout << "-------------------------------" << endl << endl;
    
    cout << "v1 ->  " << v1 << endl;
    cout << "v2 ->  " << v2 << endl << endl;
    
    cout << "Adding vectors" << endl;
    cout << "v1 + v2 -> " << v1 + v2 << endl << endl;

    cout << "Multiplying vectors" << endl;
 
    cout << "v1 * v2 -> " << v1 * v2 << endl << endl;
    
    cout << "Difference vectors" << endl;
    cout << "v1 - v2 -> " << v1 - v2 << endl << endl;
    
    cout << "Comparison > (criteria number of elements)" << endl;
    cout << "v1 > v2 -> " << (v1 > v2)<< endl << endl;
    
    cout << "Comparison < (criteria number of elements)" << endl;
    cout << "v1 < v2 -> " << (v1 < v2) << endl << endl;
    
    cout << "Comparison == (criteria number of elements)" << endl;
    cout << "v1 == v2 -> " << (v1 == v2);

    return 0;
}

Ответы (1 шт):

Автор решения: ВЛ 80

Расклад такой, что в функции

ostream &operator << (ostream &stream, const VectorOfInt &v)

v это const ссылка на объект типа VectorOfInt. Такой объект не может быть изменён (так как он const). Соответственно, вы не можете вызывать методы объекта, которые не имеют const квалификацию, так как они потенциально могут изменить этот объект, что нарушит "контракт" параметров функции - изменит состояние постоянного объекта.

Логически, метод getValue возвращает один из элементов вектора, и не меняет его видимое внешнее состояние, поэтому этот метод должен иметь квалификацию const.

Но так как этот метод на самом деле меняет один из членов класса - sts, то формально он не может быть const в том виде как есть.

Если член класса sts является сугубо внутренним делом этого класса, и никаким образом не касается внешнего наблюдаемого состояния класса, то этот член должен быть объявлен как mutable:

class VectorOfInt {
    private:
        int *data;
        size_t size;
        enum status { OK, ERR_MEM, ERR_OUT };
        mutable status sts;

mutable означает, что член класса может быть изменён внутри const метода.

Верните const в метод getValue:

const int VectorOfInt::getValue(size_t index) const

И добавьте mutable к status sts:

class VectorOfInt {
    private:
      mutable status sts;

Кстати, const квалификация возвращаемого типа (const int) не нужна, если вы возвращаете результат по значению (не как указатель или ссылку). Получатель будет способен распоряжаться этим объектом по своему усмотрению, как const или как изменяемым объектом.

То есть метод должен выглядеть так:

int VectorOfInt::getValue(size_t index) const
→ Ссылка