【问题标题】:Implementing Java Collection hierarchy in C++在 C++ 中实现 Java 集合层次结构
【发布时间】:2017-05-11 06:37:31
【问题描述】:
#include <iostream>
using namespace std;

template <typename T> class Iterator
{

T * ptr;

public: 

    Iterator(T * addr)
    {
        ptr=NULL;
        ptr=addr;
    }

    //not working
    //virtual Iterator * operator ++(int x);


    /*Iterator * operator ++(int x)
    {
        (this->ptr)++;
        return this;
    }*/

    T operator *()
    {
        return *ptr;
    }
};

template<typename T>
class Vector{

T * a;
public:
    Vector(size_t n)
    {
        a=new T[5];
    }
    T& operator [](int x)
    {
        return a[x];
    }
    class iterator: public Iterator<T>
    {
        public:

            iterator(T * addr): Iterator<T>(addr)
            {}

            /* not working 
            Iterator<T> * operator ++(int x)
            {
                Iterator<T>::ptr++;
                return this;
            }*/


            //working now
            iterator * operator ++(int x)
            {
                Iterator<T>::ptr++;
                return this;
            }
    };
    iterator begin()
    {
        iterator ob(&a[0]);
        return ob;
    }
};

int main()
{

Vector <char> v(5);

for(int i=0;i<5;i++)
    v[i]=i+65;

for(int i=0;i<5;i++)
    cout<<v[i]<<endl;

/*~~~~~~ What I want~~~~~~

Iterator <char> p=v.begin();    

*/

// what is working now:

Vector<char>:: iterator p=v.begin();

while(*p){
    cout<<*p<<endl;
    p++;
   }

   return 0;
}

在上面的代码中,我想在 Iterator 类中使操作符 ++() 成为虚拟的,以便在 main 中我可以使用:

Iterator <char> ptr=v.begin();

而不必使用:

Vector <char>:: iterator p=v.begin();

这是一个具有运行时多态性的单个基类引用,用于根据值是向量还是列表来确定调用哪个 ++ 运算符。但是,当我在 Iterator 类中将其声明为虚拟时,它不起作用。我必须专门为内部类声明它,但我想要一个单一的接口,就像在 Java 中一样。我正在尝试在 C++ 中实现 Java 集合层次结构以获得更好的结构。出了什么问题? 发生这种情况是因为 Iterator 是一个模板类,它使返回类型 Iterator 也是模板,也就是说,运算符 ++() 函数是一个模板函数?我知道模板函数不能是虚拟的,只有具体的函数可以是虚拟的。有什么办法可以解决这个问题?

【问题讨论】:

  • 为什么要在迭代器上实现运行时多态性?实际用途是什么?
  • 在 Java 中,我们只有一个 Iterator 接口,但在 C++ 中,我们使用 vector:: 迭代器和另一个用于列表的迭代器,依此类推。所以我想做的是制作一个 Iterator 基类。然后使用基类引用来调用不同的迭代器实现,例如,list 与vector 有不同的实现。所以在运行时它会根据“迭代器”引用指向的对象来确定调用谁的迭代器实现。
  • 你没有回答我。我已经知道你想要运行时多态性。我问的是为什么。就像实际用例一样。我想知道您的用例有多特别,因为我们每天都在使用的基于概念的编译时多态性已经涵盖了大多数情况。

标签: java c++ stl


【解决方案1】:

虚拟函数只能通过指针调用。您的 begin 函数不返回指针。如果你解决了这个问题,你会得到很多与类型转换相关的编译错误。

您也可以使用引用,但它应该是一个右值引用:

Iterator<char> &&p = v.begin();

【讨论】:

  • @LaurentG 是的,参考也有效,更改当前代码以使用它更容易。我更新了答案。
【解决方案2】:

这是具有正确后缀增量版本的示例实现:

template<typename T> 

class Iterator
{
    private: 
    T* ptr;
    public:
    Iterator(T* ptr1):ptr(ptr1)
    {
    }
    virtual Iterator  operator ++(int)
    {
        Iterator result(*this);
        (this->ptr)++;
        return result;
    }
    T operator*()
    {
        return *ptr;
    }
};

template<typename T>
class Vector
{
    private:
    T* data;
    public:
    Vector()
    {
        data = new T(100);
        for(int i=0;i<100;i++)
         data[i]=i;
    }


Iterator<T> begin()
{
    return Iterator<T>(&(data[0]));
}
};

【讨论】:

    【解决方案3】:

    让我先说一下,您的实现不会按您的预期工作。目前看到的所有其他答案也不会。

    使用指针作为多态迭代器的实现注定会失败,多态并不会改变您必须实现所有多态的具体迭代器这一事实。

    与 Java 类似(我会假设您很熟悉),通过接口可以实现全局多态 Iterator。现在 C++ 没有专门的接口,我们有的是纯虚拟类。

    template<typename T>
    class Iterator
    {
    public:
        virtual Iterator& operator++() = 0; // pure virtual
        // other methods
    };
    
    template<typename T>
    class Vector
    {
        class Iterator  // Vector's concrete Iterator
          : public ::Iterator<T>  // analogous to implements in Java
        {
        public:
            Iterator& operator++() override { /* implementation */ }
            // other methods...
        };
    };
    
    template<typename T>
    class List
    {
        class Iterator  // List's concrete Iterator
          : public ::Iterator<T>  // implements
        {
        public:
            Iterator& operator++() override { /* implementation */ }
            // other methods...
        };
    };
    

    由于多态性只适用于引用和指针,而 C++ 中的引用需要显式编写

    Vector<int> v;
    List<int> l;
    Iterator<int>&& rit = v.begin();
    const Iterator<int>& crit = l.begin();
    

    是你将如何使用Iterator

    最后,多态性是一种工具,滥用它比没有它更糟糕。请务必考虑性能损失并权衡其提供的灵活性。

    【讨论】:

    • 感谢您的回答。你提到的关于性能的最后两行,你能详细说明一下性能惩罚吗?我是 C++ 编程的新手,我只使用 C++ 编写数据结构,但从未使用 C++ 将一些东西紧凑为一个单元,所以这是我的第一次尝试,所以你能分享更多关于你提到的性能损失的信息吗?谢谢你..
    • @DeepayanGhosh Thisthis 是很好的起点。已经有广泛的讨论了,我不再赘述。我要说的是容器应该适合它的需求,因为它是模板化的,所以它通常很广泛。
    • 感谢您的帮助。从这些问题中学到了很多东西。谢谢
    【解决方案4】:

    您的代码几乎可以工作。我只需要解决其中的 3 个问题:

    • 如果您希望能够在派生类的重写方法中访问它,ptr 应该在 Iterator 类中受到保护而不是私有
    • 增量运算符应声明为virtual Iterator&lt;T&gt; ...
    • 如果您想将数组迭代到一个空值,您应该在最后写入一个空值。

    所以编译时没有警告,并且在 Clang 3.4.1 中运行良好:

    #include <iostream>
    using namespace std;
    
    template <typename T> class Iterator
    {
    protected:
    T * ptr;
    
    public: 
    
        Iterator(T * addr)
        {
            ptr=NULL;
            ptr=addr;
        }
    
        //not working - in fact works perfectly
        virtual Iterator<T> * operator ++(int x)
        {
            (this->ptr)++;
            return this;
        }
    
        T operator *()
        {
            return *ptr;
        }
    };
    
    template<typename T>
    class Vector{
    
    T * a;
    public:
        Vector(size_t n)
        {
            a=new T[5];
        }
        T& operator [](int x)
        {
            return a[x];
        }
        class iterator: public Iterator<T>
        {
            public:
    
                iterator(T * addr): Iterator<T>(addr)
                {}
    
                /* not working 
                Iterator<T> * operator ++(int x)
                {
                    Iterator<T>::ptr++;
                    return this;
                }*/
    
    
                //working now but useless as we can use the base class version
                /*iterator * operator ++(int x)
                {
                    Iterator<T>::ptr++;
                    return this;
                }*/
        };
        iterator begin()
        {
            iterator ob(&a[0]);
            return ob;
        }
    };
    
    int main()
    {
    
    Vector <char> v(5);
    
    for(int i=0;i<5;i++)
        v[i]=i+65;
    
    for(int i=0;i<5;i++)
        cout<<v[i]<<endl;
    
    v[5] = 0;  // set a null at the end of the vector
    
    /*~~~~~~ What I want~~~~~~ and that works...*/
    
    Iterator <char> p=v.begin();    
    
    
    
    // what is working now:
    
    //Vector<char>:: iterator p=v.begin();
    
    while(*p){
        cout<<*p<<endl;
        p++;
       }
    
       return 0;
    }
    

    您可以在 Vector 类中取消注释 operator ++ 的覆盖版本,它也可以正常工作。

    【讨论】:

      猜你喜欢
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多