Что я делаю не так с перегрузкой оператора? - PullRequest
0 голосов
/ 30 ноября 2018

Я не понимаю, что не так, когда я перегружаю оператор + (цель этого состоит в том, чтобы объединить 2 стека в один новый) ... он возвращает "сумму", но изменяет значения для предыдущих.///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

template <typename T>
classStack
{
    private:

        struct Node
        {
            T data;
            Node *next;
        } *top;

        std::size_t size;

    public:
        Stack();
        ~Stack();
        void            push(T data);
        void            pop(void);
        size_t          get_size(void);
        const Stack&    operator=(const Stack &stack_obj);
        const Stack     operator+(const Stack &stack_obj);
        void            show_all_stack(void);
};


template <typename T>
const Stack<T>  Stack<T>::operator+(const Stack &stack_obj)
{
    Stack   stack;
    Node    *tmp;

    if (!this->size && !stack_obj.size) {
        return stack;
    }
    if (!stack_obj.size)
    {
        stack.size = size;
        stack.top = top;
    }
    else if (!size)
    {
        stack.size = stack_obj.size;
        stack.top = stack_obj.top;
    }
    else
    {
        stack.size = size + stack_obj.size;
        stack.top = new Node;
        stack.top = top;    
        tmp = stack.top;
        while (tmp->next)
            tmp = tmp->next;
        tmp->next = new Node;
        tmp->next = stack_obj.top;
   }
   return stack;
 }

Конструктор по умолчанию

template <typename T>
Stack<T>::Stack(void): top(nullptr), size(0)
{   
}

Деструктор

template <typename T>
Stack<T>::~Stack(void)
{
    Node    *next;

    if (!size)
        std::cout << "Stack is empty!\n";
    else
    {
        while (top != nullptr)
        {
            next = top->next;
            delete top;
            top = next;
        }
        top = nullptr;
    }
}

Оператор присваивания

template <typename T>
const Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
    Node    *tmp;
    Node    *ptr;
    Node    *last;
    Node    *new_node;

    if (&stack_obj != this)
    {
        while (top != nullptr)
        {
            tmp = top;
            top = top->next;
            delete tmp;
        }
        top = nullptr;
        size = stack_obj.size;
        ptr = stack_obj.top;
        while (ptr)
        {
            new_node = new Node;
            new_node->data = ptr->data;
            new_node->next = nullptr;
            if (!top)
            {
                top = new_node;
                last = new_node;
            }
            else
            {
                last->next = new_node;
                last = new_node;
            }
            ptr = ptr->next;
        }
    }
}

1 Ответ

0 голосов
/ 30 ноября 2018

Перед созданием функций, которые возвращают Stack<T> по значению, или имеют функции, которые требуют семантики копирования для Stack<T> (как в operator +), необходимо убедиться, что Stack<T> безопасно для копирования.В данный момент вам не хватает конструктора копирования, поэтому ваш operator + никогда не будет работать правильно, даже если сама функция не содержит ошибок.

Вам не хватает этой функции:

Stack::Stack(const Stack<T>&)

Самый простой способ реализовать конструктор копирования - это извлечь большую часть кода из оператора присваивания и поместить его в конструктор копирования.Более или менее, код должен выглядеть примерно так (код не был скомпилирован или протестирован - он иллюстрирует основной смысл этого ответа):

template <typename T>
Stack<T>::Stack<T>(const Stack<T> &stack_obj) : top(nullptr), size(0)
{
    Node    *tmp;
    Node    *ptr;
    Node    *last;
    Node    *new_node;

    ptr = stack_obj.top;
    while (ptr)
    {
        new_node = new Node;
        new_node->data = ptr->data;
        new_node->next = nullptr;
        if (!top)
        {
            top = new_node;
            last = new_node;
        }
        else
        {
            last->next = new_node;
            last = new_node;
        }
        ptr = ptr->next;
    }
}

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

Теперь, когда у вас есть конструктор копирования и деструктор, вы можетеТеперь напишите оператор присваивания.Используемая здесь техника - это идиома копирования / обмена

#include <algorithm>
//...
template <typename T>
Stack<T>& Stack<T>::operator=(const Stack<T> &stack_obj)
{
    if ( &stack_obj != this )
    {
        Stack<T> temp(stack_obj);
        std::swap(top, temp.top);
        std::swap(size, temp.size);
    }
    return *this;
}

Верьте или нет, это работает.Код, который был здесь, был перемещен в конструктор копирования, и, таким образом, оператор присваивания использует конструктор копирования.

Для краткого пояснения код создает временный объект Stack<T> изпередано в stack_obj (вот почему вам нужен конструктор рабочей копии).Затем все, что нужно сделать, это поменять this членов с временными членами.Наконец, temp умирает со старыми данными (вот почему деструктор должен работать правильно).

Обратите внимание, что вам нужно поменять местами все члены, поэтому, если вы добавите больше членов в класс Stack<T>, вам необходимо поменять их местами в операторе присваивания.

Как только вы получитеОсновные 3 функции (копирование, назначение, уничтожение) написаны правильно, тогда и только тогда вы должны писать функции, которые возвращают Stack<T> по значению, или писать функции, которые принимают Stack<T> по значению.

У вас могут быть другие проблемы с operator +, которые выходят за рамки того, что этот ответ представляет вам, но суть в том, что ваш класс требует, чтобы он имел правильную семантику копирования перед реализацией +,

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