operator++ 重载如何迭代我的 LinkedList

How does operator++ overloading work to iterate over my LinkedList

这是我的 LinkedList 命名空间

namespace LinkedList {     
    template<class T>
    class Node{
    public:
        Node(const T& data)
            :data_(data), next_(nullptr) {}
        T data_;
        Node<T> *next_;

        Node<T> *operator++(){
            return next_;
        }
    };


    

    template<class T>
    class LinkedList{
    public:
        LinkedList()
            : head_(nullptr), tail_(nullptr) {}
        
        ~LinkedList(){
            Node<T> *curr = head_;
            Node<T> *next;
            while(curr != nullptr){
                next = curr->next_;
                delete curr;
                curr = next;
            }
        }
        void Append(const T& data) {
            Node<T> *tmp = new Node<T>(data);
            if(head_ == nullptr) {
                head_ = tmp;
                tail_ = tmp;
            } else if(head_ == tail_){
                head_->next_ = tmp;
                tail_ = tmp;
            } else {
                tail_->next_ = tmp;
                tail_ = tmp;
            }
        }

        void Present(){
            for(Node<T> *curr = head_; curr != nullptr; curr=curr->next_){
                std::cout << curr->data_ << std::endl;
            }
        }

        Node<T> *begin(){
            return head_;
        }

        Node<T> *end(){
            return nullptr;
        }
    private:
        Node<T> *head_;
        Node<T> *tail_;
    };
}

我正在阅读迭代器并想让我的 LinkedList 对象与基于范围的 for 循环兼容。这是我从阅读基于范围的 for 循环中得到的

for(auto x: list){ }

等同于

for(; begin != end; ++begin) { //*begin};

我以为我很厚颜无耻,可以跳过几个运算符重载 (!=, *) 的步骤,让我的 LinkedList 可以通过将我的迭代器编程到我的节点 class 中来使用基于范围的 for 循环 for no除此之外还有其他原因,我喜欢它。这只是我学习 C++ 的第二天,所以这可能是一个愚蠢的问题,但我仍然对为什么这不起作用感到困惑:

LinkedList::LinkedList<int> list;
list.Append(3);
list.Append(5);
for(auto x: list) { //blah blah blah}

我知道我的前缀增量是核心问题,当for循环执行++__begin时,我希望它做的是___begin=_开始->next 但是它没有。为什么是这样?在我看来,运算符重载的工作方式是,无论我在重载函数中引用什么成员变量,它都是从我正在操作的实例中引用的。当我 return ptr 时,它正在将我正在操作的任何实例设置到这个 ptr。我知道我对此的理解是错误的,因为它不起作用,所以请有人向我解释它实际上是如何工作的,哈哈。

您写了一个

template<class T>
Node<T>* Node<T>::operator++();

会像

一样被调用
Node<int> n;
Node<int> *p = ++n; // calls the pre-increment operator

请注意,这与 canonical form

完全不同
Node<T>& Node<T>::operator++();

其中 returns 对可在表达式中使用的递增对象的引用。

但还有另一个问题:operator overloading 有效

When an operator appears in an expression, and at least one of its operands has a class type or an enumeration type, ...

但是 Node<T>* 不是 class 类型。它是一个指针,指针已经有自己的内置运算符。你不能超载他们。没有Node<T>*::operator++().

写一个迭代器。还不错,而且它们确实有效!


注意。迭代器旨在泛化指针,并具有兼容的接口。如果您的容器基本上是一个数组,您可以使用原始指针 - 因为递增指针已经是迭代数组的正确方法。

只有当我们想要提供对非连续结构的类似数组或类似指针的访问时,我们才需要做这些额外的工作。