简体   繁体   English

带有迭代器实现的列表 ADT 的 C++ 模板化接口

[英]C++ Templated Interface for a List ADT with iterators Implementation

I'd like to have an interface for the List ADT which provides the user with iterators.我想为 List ADT 提供一个接口,它为用户提供迭代器。 Currently I have the following for the iterator:目前我有以下迭代器:

template <typename D>
class   IIterator
{
    public:
        virtual D           &operator*(void) = 0;
        virtual IIterator   &operator++(void) = 0;
        virtual bool        operator==(const IIterator &rhs)    const = 0;
        virtual bool        operator!=(const IIterator &rhs)    const = 0;
        virtual IIterator   &operator--(void) = 0;
};

And this for the List interface, which uses the iterator interface above:这是 List 接口,它使用上面的迭代器接口:

# include "IIterator.hpp"

template <typename D>
class   IList
{
    public:
        virtual IIterator<D>    begin(void) const = 0;
        virtual IIterator<D>    end(void)   const = 0;
        virtual void            insertFront(const D &e) = 0;
        virtual void            insertBack(const D &e) = 0;
        virtual void            insert(const IIterator<D> &p, const D &e) = 0;
        virtual void            eraseFront(void) = 0;
        virtual void            eraseBack(void) = 0;
        virtual void            erase(const IIterator<D> &p);
};

I can abandon the iterator interface, it's not required by the assignment, but the List has to implement a pure virtual interface.我可以放弃迭代器接口,赋值不需要它,但是List必须实现一个纯虚拟接口。 The thing is, if I discard IIterator , I don't know if it's possible to have IList::insert() and IList::erase() in it anymore, since they take not only the template argument but also the Iterator that is to be implemented in the class inheriting the interface.问题是,如果我丢弃IIterator ,我不知道是否可以再在其中包含IList::insert()IList::erase() ,因为它们不仅采用模板参数,还采用 Iterator在继承接口的类中实现。

The following List implementation inherits from IList and uses doubly linked list.以下 List 实现继承自IList并使用双向链表。 It doesn't compile:它不编译:

template <typename D>
class   NodeList : public IList<D>
{
    private:
        struct  Node
        {
            D       data;
            Node    *prev;
            Node    *next;
        };
    public:
        class   Iterator : public IIterator<D>
        {
            public:
                D           &operator*(void);
                bool        operator==(const IIterator<D> &p)   const;
                bool        operator!=(const IIterator<D> &p)   const;
                Iterator    &operator++(void);
                Iterator    &operator--(void);
            private:
                Iterator(Node *node);
                Node        *_ptr; 
        };
        NodeList(void);
        ~NodeList(void);
        NodeList(const NodeList &copy);
        NodeList            &operator=(const NodeList &rhs);
        int                 size(void)  const;
        bool                empty(void) const;
        IIterator<D>        begin(void) const;
        IIterator<D>        end(void)   const;
        void                insertFront(const D &e);
        void                insertBack(const D &e);
        void                insert(const Iterator &p, const D &e);
        void                eraseFront(void);
        void                eraseBack(void);
        void                erase(const Iterator &p);
    private:
        int                 _n;
        Node                *_header;
        Node                *_trailer;
};

It outputs the following error:它输出以下错误:

./../../libft/NodeList.hpp:52:11: error: 'NodeList<int>::insert' hides overloaded virtual function [-Werror,-Woverloaded-virtual]
                void                            insert(const Iterator &p, const D &e);
                                                ^
main.cpp:27:17: note: in instantiation of template class 'NodeList<int>' requested here
        NodeList<int>           seq2;
                                ^
./../../libft/IList.hpp:26:18: note: hidden overloaded virtual function 'IList<int>::insert' declared here: type mismatch at 1st parameter
      ('const IIterator<int> &' vs 'const NodeList<int>::Iterator &')
                virtual void                    insert(const IIterator<D> &p, const D &e) = 0;
                                                ^

Doesn't subtype polymorphism let the IList interface know that NodeList<int>::Iterator is IIterator<int> 's subclass therefore the virtual function insert() is not hidden but rather properly overloaded?子类型多态性不是让IList接口知道NodeList<int>::IteratorIIterator<int>的子类,因此虚函数insert()不是隐藏的而是正确重载的? (the same error is output concerning erase() ) (关于erase()输出相同的错误)

I believe there's a terrible design flaw, could you please tell me what can be replaced, reworked and how else I can achieve the needed result?我相信有一个可怕的设计缺陷,你能告诉我什么可以更换,返工以及我如何才能达到所需的结果?

There are many issues and caveats with both the general design and code here, but let's focus on the specific question you are asking:这里的一般设计和代码都有很多问题和注意事项,但让我们关注您提出的具体问题:

If the base class' method returns a IIterator<D> by value , then that's the only type that subclasses will be allowed to return for their overloads.如果基类的方法按value返回IIterator<D> ,那么这是允许子类为其重载返回的唯一类型。

You "could" have the base return a pointer to a IIterator<D> , and have the appropriate subclass instantiated in overloads but...你“可以”让基类返回一个指向IIterator<D>的指针,并在重载中实例化适当的子类,但是......

Virtual overloaded operators are a massive pain to deal with, so having a one-size-fit-all type being returned is actually a really good thing if you want to maintain iterators that feel like pointers.虚拟重载运算符处理起来非常痛苦,因此如果您想维护感觉像指针的迭代器,返回一个通用的类型实际上是一件非常好的事情。

Instead, you should use the pimpl pattern to hide the implementation details of the current class in a member of the iterator, while keeping the iterator a value type.相反,您应该使用 pimpl 模式将当前类的实现细节隐藏在迭代器的成员中,同时保持迭代器的值类型。

It would look roughly like this:它大致如下所示:

template <typename D>
class Iterator
{
public:
    class Impl {
    public:
        virtual D*   get() = 0;
        virtual void inc() = 0;
        virtual void dec() = 0;
    };

    explicit Iterator(std::unique_ptr<Impl> impl) 
        : impl_(std::move(impl)) {}

    D&        operator*() { return *impl_->get(); }
    Iterator& operator++() { impl_->inc(); return *this; }
    Iterator& operator--() { impl_->dec(); return *this; }
        
    bool operator==(const Iterator& rhs) const  {
       return impl_->get() == rhs.impl_->get();
    }

    // Modern C++ (C++-20 and up) synthesizes operator!=() from operator==().

private:
    std::unique_ptr<Impl> impl_;
};

template <typename D>
class NodeList
{
  // ...
private:
    class IteratorImpl : public Iterator<D>::Impl
    {
    public:
        D*   get() override;
        void inc() override;
        void dec() override;
    private:
        Iterator(Node* node);
        Node* _ptr; 
    };

public:
    Iterator<D> begin() const override  {
      return Iterator<D>{std::make_unique<Iterator>(this)};
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM