Перегрузка оператора C ++ - «воссоздание вектора» - PullRequest
1 голос
/ 02 апреля 2010

Я в настоящее время нахожусь на курсе программирования второго уровня коллажа ... Мы работаем над перегрузкой операторов ... для этого мы должны перестроить векторный класс ... Я строил класс и обнаружил, что большая часть его основана на [] operator. Когда я пытался реализовать + operator, я столкнулся со странной ошибкой, которую мой профессор раньше не видел (очевидно, с тех пор, как класс переключил IDE с MinGW на VS express ...) (я использую Visual Studio Express 2008 C ++ edition. ..)

vector.h

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

#ifndef _VECTOR_H
#define _VECTOR_H

const int DEFAULT_VECTOR_SIZE = 5;

class Vector
{
private:
    int *   data;
    int     size;
    int     comp;
public:
    inline  Vector      (int Comp = 5,int Size = 0) 
        : comp(Comp), size(Size)    { if (comp > 0) { data = new int [comp]; } 
                                      else { data = new int [DEFAULT_VECTOR_SIZE];
                                      comp = DEFAULT_VECTOR_SIZE; }
                                    }
    int      size_      ()          const       { return size; }
    int      comp_      ()          const       { return comp; }
    bool     push_back  (int);
    bool     push_front (int);
    void     expand     ();
    void     expand     (int);
    void     clear      ();
    const    string at  (int);
    int&         operator[ ](int);
    int&         operator[ ](int) const;
    Vector&  operator+  (Vector&);
    Vector&  operator-  (const Vector&);
    bool     operator== (const Vector&);
    bool     operator!= (const Vector&);

    ~Vector() { delete [] data; }
};

ostream& operator<< (ostream&, const Vector&);

#endif

Vector.cpp

#include <iostream>
#include <string>
#include "Vector.h"
using namespace std;

const string Vector::at(int i) {
    this[i];
}

void Vector::expand() {
    expand(size);
}

void Vector::expand(int n ) {
    int * newdata = new int [comp * 2];
    if (*data != NULL) {
        for (int i = 0; i <= (comp); i++) {
            newdata[i] = data[i];
        }
        newdata -= comp;
        comp += n;
        data = newdata;
    delete newdata;
    }
    else if ( *data == NULL || comp == 0) {
        data = new int [DEFAULT_VECTOR_SIZE];
        comp = DEFAULT_VECTOR_SIZE;
        size = 0;
    }
}

bool Vector::push_back(int n) {
    if (comp = 0) { expand(); }
    for (int k = 0; k != 2; k++) {
        if ( size != comp ){
            data[size] = n;
            size++;
            return true;
        }
        else {
            expand();
        }
    }
    return false;
}

void Vector::clear() {
    delete [] data;
    comp = 0;
    size = 0;
}
int& Vector::operator[] (int place) { return (data[place]); }
int& Vector::operator[] (int place) const { return (data[place]); }

Vector& Vector::operator+ (Vector& n) {
    int temp_int = 0;

    if (size > n.size_() || size == n.size_()) { temp_int = size; }
    else if (size < n.size_()) { temp_int = n.size_();  }

    Vector newone(temp_int);
    int temp_2_int = 0;

    for ( int j = 0; j <= temp_int && 
                     j <= n.size_() && 
                     j <= size; 
                                        j++) {
        temp_2_int = n[j] + data[j];
        newone[j] = temp_2_int;
    }
////////////////////////////////////////////////////////////
    return newone;
////////////////////////////////////////////////////////////
}

ostream& operator<< (ostream& out, const Vector& n) {
    for (int i = 0; i <= n.size_(); i++) {
////////////////////////////////////////////////////////////
        out << n[i] << " ";
////////////////////////////////////////////////////////////
    }
    return out;
}

Ошибка:

out << n[i] << " "; error C2678:

бинарный '[': оператор не найден, который принимает левый операнд типа 'const Vector' (или нет допустимое преобразование)

return newone;

ошибка C2106: '=': слева операнд должен иметь значение l


Как указывалось выше, я учусь на факультете компьютерных наук, так как я выбрал специальность, я был бы признателен за советы, советы и более эффективные способы работы: D

Ответы [ 6 ]

10 голосов
/ 02 апреля 2010

Это:

int operator[ ](int);

- неконстантная функция-член. Это означает, что он не может быть вызван на const Vector.

Обычно оператор нижнего индекса реализован таким образом, что он возвращает ссылку (если вы возвращаете значение, как вы делаете, вы не можете использовать его как lvalue, например, вы не можете сделать newone[j] = temp_2_int;, как у вас есть в вашем коде):

int& operator[](int);

Чтобы иметь возможность вызывать его для const-объекта, вы также должны предоставить const-версию функции-члена:

const int& operator[](int) const;

Поскольку вы спрашиваете «советы, указатели и лучшие способы сделать что-то:»

  • Вы не можете назвать своего включенного охранника _VECTOR_H. Имена, начинающиеся с подчеркивания, за которым следует заглавная буква, зарезервированы для реализации. Есть много правил о подчеркивании .
  • Вы должны никогда использовать using namespace std в заголовке.
  • Ваш operator+ должен взять const Vector&, поскольку он не собирается изменять свой аргумент.
  • Ваш at должен возвращать int и должен соответствовать семантике контейнеров стандартной библиотеки C ++ (т. Е. Он должен выдавать исключение, если i выходит за пределы. Вам нужно использовать (*this)[i] для вызова ваш перегружен operator[].
  • Вам необходимо узнать, что делает оператор *. В некоторых местах вы путали указатели и объекты, на которые они указывают.
  • Остерегайтесь путаницы = с == (например, в if (comp = 0)). Компилятор будет предупреждать вас об этом. Не игнорируйте предупреждения.
  • Ваша логика будет намного проще, если вы гарантируете, что data никогда не равен NULL.
2 голосов
/ 02 апреля 2010

Не могу вписать это в комментарий к ответу Нейла, поэтому мне придется более подробно здесь остановиться.

Относительно вашей функции expand(). Похоже, что работа этой функции заключается в расширении внутреннего хранилища, в котором есть элементы comp, элементами n при сохранении size вектора. Итак, давайте пройдемся по тому, что у вас есть.

void Vector::expand(int n) {
    int * newdata = new int [comp * 2];

Хорошо, вы только что создали новый массив, который в два раза больше старого. Ошибка: почему новый размер не имеет ничего общего с n?

    if (*data != NULL) {

Ошибка: *data - это первый int элемент в вашем массиве. Это не указатель. Почему его сравнивают с NULL?

Ошибка концепции: Даже если вы сказали if (data != NULL), что может быть проверкой, чтобы увидеть, существует ли вообще массив, в какой момент времени data когда-либо установлен в NULL? new [] не возвращает NULL, если не хватает памяти; это исключение.

        for (int i = 0; i <= (comp); i++) {
            newdata[i] = data[i];
        }

Предупреждение. Вы копируете весь массив, но допустимы только первые size элементы. Цикл может просто дойти до size, и все будет в порядке.

        newdata -= comp;

Ошибка: неверный указатель математики. newdata установлен на указатель, который знает, где (comp int s назад с начала newdata ?!), и почти наверняка указатель, который повредит память, если задан delete [].

        comp += n;

Это нормально, для чего это.

        data = newdata;
        delete newdata;
    }

Ошибка: вы сохранили указатель и сразу же удалили его память, сделав его недопустимым указателем.

    else if ( *data == NULL || comp == 0) {
        data = new int [DEFAULT_VECTOR_SIZE];
        comp = DEFAULT_VECTOR_SIZE;
        size = 0;
    }
}

Ошибка: это должно быть в вашем конструкторе, а не здесь. Опять же, ничто никогда не устанавливает data в NULL, а *data является int, а не указателем.

Что эта функция должна делать:

  • создать новый массив comp + n элементов
  • копирование size элементов из старого массива в новый
  • удалить старый массив
  • установить data для указания на новый массив

Удачи.

2 голосов
/ 02 апреля 2010

Кроме того, что другие уже писали о вашем operator[]():

Ваш operator+() принимает правую сторону для ссылки, не относящейся к const, как если бы он пытался ее изменить. Однако с A+B все ожидают, что B останется без изменений.

Кроме того, я бы реализовал все бинарные операторы, одинаково обрабатывая свои операнды (т.е. не меняя ни один из них) как функции, не являющиеся членами. В качестве функций-членов левая часть (this) может обрабатываться по-разному. (Например, он может быть перезаписан версиями в производных классах.)

Тогда, IME, всегда хорошо основывать operator+() на operator+=(). operator+=() не обрабатывает свои операнды одинаково (он меняет свой левый), поэтому лучше всего выполнять его как функцию-член. Как только это будет сделано, реализация operator+() поверх него станет просто куском.

Наконец, operator+() никогда не должен, никогда не возвращать ссылку на объект. Когда вы говорите A+B, вы ожидаете, что это вернет новый объект, а не изменит какой-либо существующий объект и вернет ссылку на него.

1 голос
/ 02 апреля 2010

В вашем коде так много ошибок, что трудно понять, с чего начать. Вот один из них:

 delete [] data;
 *data = *newdata;

Вы удаляете указатель, а затем немедленно разыменовываете его.

И

const string Vector::at(int i) {
    this[i];
}

Это (я думаю) вектор целых чисел. почему это возвращает строку? И применение оператора [] к этому не вызывает перегрузки вашего оператора [] - он обрабатывает это как массив, который не является.

1 голос
/ 02 апреля 2010

Вам необходимо предоставить две версии вашего оператора []. Для доступа:

T operator[](std::size_t idx)const;

Для записи в элемент:

T& operator[](std::size_t idx);

В обоих вышеперечисленных случаях замените T типом элементов. Причиной возникновения этой проблемы является то, что только функции, помеченные как «const», могут вызываться для объекта, объявленного как «const». Обозначение всех неизменяемых функций как «const» - это определенно то, что вы должны сделать, и это называется «const-правильность». Поскольку возврат ссылки на элемент (необходимый для записи) позволяет мутировать базовый объект, эта версия функции не может быть сделана "const". Следовательно, необходима только постоянная перегрузка «const».

Вы также можете быть заинтересованы в чтении:

0 голосов
/ 02 апреля 2010
int Vector::operator[] (int place) { return (data[place]); }

Это должно быть

int Vector::operator[] (int place) const { return (data[place]); }

, чтобы вы могли выполнить операцию [] для константных векторов. const после объявления функции означает, что экземпляр класса (this) обрабатывается как const Vector, что означает, что вы не сможете изменять обычные атрибуты. Или другими словами: метод, который имеет доступ только для чтения к атрибутам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...