有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何编写以通用方式接受迭代器或集合的函数?

我过去8年来一直是java程序员,最近我一直在玩C++。这是我在C++ STL和java中遇到的一个问题,p>

在Java中,您可以编写一个采用迭代器的方法,如下所示:

void someMethod(Iterator<String> data) {
    // ...
}

传入一个Iterator,该方法不需要知道该迭代器的底层集合是什么,这很好

在C++中,没有迭代器的公共基类(据我所知)。我必须写一个这样的函数:

void some_function(std::vector<std::string>::const_iterator data) {
    // ...
}

换句话说,some_function知道迭代器是vector上的迭代器。这并不好,因为我希望函数能够工作,而不管迭代器的底层集合是什么

如何在C++中实现这一点?如果它不是真的可能,那么什么是最好的方法来创建C++中的函数,它将集合作为参数,但不需要知道集合的确切类型是什么?p>

附录

谢谢你的回答。除了答案之外,我在Nicolai M.Josuttis的书The C++ Standard Library: A Tutorial and Reference的第7.5段(迭代器特征)中找到了一些关于这方面的好信息。第7.5.1段解释了如何为不同迭代器类别编写函数的专用版本


共 (4) 个答案

  1. # 1 楼答案

    最好通过命名约定指出迭代器的类型,以及迭代器需要拥有的属性类型。下面是迭代器的一些常见命名约定:

    template<typename Iterator>
    void foo_iterator(Iterator begin, Iterator end)
    {
       typedef typename std::iterator_traits<Iterator>::value_type T;
       ....
    }
    
    template<typename RandomIterator>
    void foo_random_iterator(RandomIterator begin, RandomIterator end)
    {
       typedef typename std::iterator_traits<RandomIterator>::value_type T;
       ....
    }
    
    template<typename ForwardIterator>
    void foo_forward_iterator(ForwardIterator begin, ForwardIterator end)
    {
       typedef typename std::iterator_traits<ForwardIterator>::value_type T;
       ....
    }
    
    template<typename ReverseIterator>
    void foo_forward_iterator(ReverseIterator begin, ReverseIterator end)
    {
       typedef typename std::iterator_traits<ReverseIterator>::value_type T;
       ....
    }
    
    template<typename InputIterator>
    void foo_input_iterator(InputIterator begin, InputIterator end)
    {
       typedef typename std::iterator_traits<InputIterator>::value_type T;
       ....
    }
    
    template<typename OutputIterator>
    void foo_output_iterator(OutputIterator out)
    {
       // We don't have a type T, as we can't "always"
       // know the type, as this type of iterator is a sink.
       ....
    }
    

    下面是序列类型容器的通用定义,其中包括vector和deque

    template <typename T,
              class Allocator,
              template <class,class> class Sequence>
    inline void foo_sequence(Sequence<T,Allocator>& sequence)
    {
       ....
    }
    
  2. # 2 楼答案

    可以使用header file 并指定迭代器必须支持的最低要求

    因此,在上面的示例中,您可能希望将函数重写为:

    template<typename T>
    void some_function(std::forward_iterator<T> data) {
       ...
    }
    

    对于要求只能在集合中向前移动迭代器(++)的内容

  3. # 3 楼答案

    你可能想考虑函数模板。看看一些std{}函数模板是如何工作的,比如std::for_each

    例如

    template< class Iterator >
    void some_function( Iterator first, Iterator last )
    {
        // ...
    }
    

    然后,您可以使用多种iterable范围调用从该模板生成的函数

    例如

    std::vector< double > my_doubles;
    // ... populate doubles
    some_function( my_doubles.begin(), my_doubles.end() );
    
    
    std::set< Custom > my_custom_class_set;
    // ... populate ...
    some_function( my_custom_class_set.begin(), my_custom_class_set.end() );
    
    int raw_array[50];
    // ... populate ...
    some_function( raw_array, raw_array + 50 );
    
  4. # 4 楼答案

    这是C++和java之间的一个很大的区别。Java唯一的抽象工具是运行时多态性(接口和抽象类)。在C++中,你不限于此。可以为类型创建别名,并让类具有其他关联/嵌套类型。在很多情况下,它可以让你不受运行时多发性的影响。编译时类泛型的优点是速度非常快(没有虚拟函数调用,也没有内联的可能性)。此外,当你没有垃圾收集器时,它还简化了生活管理。只需在堆栈上创建对象即可

    下面是一个(未经测试的)示例:

    template<typename Iter>
    typename std::iterator_traits<Iter>::value_type
    sum(Iter begin, Iter end) {
       typedef typename std::iterator_traits<Iter>::value_type vt;
       vt accum = vt();
       while (begin!=end) {
          accum += *begin;
          ++begin;
       }
       return accum;
    }
    

    在这里,“Iter”只是一个名字。它实际上没有对类型施加任何约束。如果你想用一个不是迭代器的类型(至少在结构上)实例化这个模板,你会得到一个编译时错误(编译时duck类型)。所以,你工作的一部分是记录你期望的类型。这通常是通过选择模板参数(即ForwardIterator)和注释的一些描述性名称来实现的

    我还应该提到的是,如果您将这个函数模板与各种迭代器一起使用,那么多个“sum”函数将被“实例化”。如果你不想要这种代码复制和/或真的需要运行时多态性,你可以应用一种叫做“类型擦除”的技术。不过,迭代器的类型擦除不是标准库的一部分。而且,我从未觉得有必要将这种技术应用于迭代器。但是在其他库中,比如boost::any和boost::function中,您会发现类型擦除的用法

    您还可以使用其他一些模板技巧来区分不同的迭代器类别(请参见“标记分派”)或约束函数模板(请参见“SFINAE”)。如果您对类型删除感兴趣,请尝试Google C++,类型擦除,迭代器。基本上可以创建一个句柄类(通过指针)来管理多态对象。这个多态对象包装了另一个你想“擦除”(隐藏)其类型的对象