繁体   English   中英

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

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

我想为 List ADT 提供一个接口,它为用户提供迭代器。 目前我有以下迭代器:

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;
};

这是 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);
};

我可以放弃迭代器接口,赋值不需要它,但是List必须实现一个纯虚拟接口。 问题是,如果我丢弃IIterator ,我不知道是否可以再在其中包含IList::insert()IList::erase() ,因为它们不仅采用模板参数,还采用 Iterator在继承接口的类中实现。

以下 List 实现继承自IList并使用双向链表。 它不编译:

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;
};

它输出以下错误:

./../../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;
                                                ^

子类型多态性不是让IList接口知道NodeList<int>::IteratorIIterator<int>的子类,因此虚函数insert()不是隐藏的而是正确重载的? (关于erase()输出相同的错误)

我相信有一个可怕的设计缺陷,你能告诉我什么可以更换,返工以及我如何才能达到所需的结果?

这里的一般设计和代码都有很多问题和注意事项,但让我们关注您提出的具体问题:

如果基类的方法按value返回IIterator<D> ,那么这是允许子类为其重载返回的唯一类型。

你“可以”让基类返回一个指向IIterator<D>的指针,并在重载中实例化适当的子类,但是......

虚拟重载运算符处理起来非常痛苦,因此如果您想维护感觉像指针的迭代器,返回一个通用的类型实际上是一件非常好的事情。

相反,您应该使用 pimpl 模式将当前类的实现细节隐藏在迭代器的成员中,同时保持迭代器的值类型。

它大致如下所示:

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