65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Functors 对 Composite 进行条件迭代

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.47/5 (7投票s)

2004年10月8日

5分钟阅读

viewsIcon

44002

downloadIcon

543

使用 functor 在迭代复合对象时条件性地返回值。

引言

我之前已经写了两篇关于复合模式的文章。第一篇构建了一个基本的复合体,并介绍了各种遍历复合体层次结构的方法。第二篇文章展示了一种相对干净的方法来迭代复合体,仅提取特定类型的对象。本文将扩展我第二篇文章的概念,允许使用 functor 在迭代过程中选择要返回的对象。

背景

我关于复合模式的第一篇文章是 Composites and Visitors。这篇文章提供了一个通用的复合体,以及用于对复合体进行浅层和深度迭代的各种基本迭代器。它还涵盖了一些关于在复合体上定义访问序列的策略。

我关于复合模式的第二篇文章是关于创建新的浅层和深层迭代器,这些迭代器仅返回特定类型的对象。本文可以在以下位置找到:Typed Iteration over a Composite

本文是我第二篇文章的泛化。提供浅层和深层迭代器,这些迭代器返回从函数对象或 functor 返回 true 的对象。首先要解决的明显问题是“什么是 functor?”。简单来说,functor 是一个包含重载函数调用运算符 operator() 的类。functor 可以像对象一样传递,但又可以像函数一样使用:因此得名函数对象。它们实际上是一种面向对象的方式,可以做一些类似于函数指针的事情,但具有语法极其简单的明显优势。我的基本函数对象声明在复合基类内部,主要是为了能够访问模板参数,尽管没有理由不能在单独的文件中声明它。

class base_functor
{
public:
    virtual ~base_functor() {}    // Force base functor to be virtual
    // Pure virtual operator() and Clone
    virtual bool operator()( const T* value ) const = 0;
    virtual base_functor *Clone() const = 0;
};

当你继承 base_functor 时,你必须声明重载的函数调用运算符,以及一个 Clone 函数。函数调用运算符将执行繁重的工作,而 Clone 函数是一些“管道”工作,用于确保迭代器在需要时可以复制 functor。

例如,我创建了 2 个 functor,它们都声明为我根复合节点内的内部类。第一个是一个简单的类型比较 functor,它镜像了我上一篇文章中呈现的功能。

template <typename T>
class CTypeComparisonFunctor : public base_functor
{
public:
    virtual bool operator()( const CNodeBase* value ) const
    {
        return dynamic_cast<const T*>( value ) != NULL;
    }
    virtual base_functor *Clone() const
    {
        return new CTypeComparisonFunctor<T>( *this );
    }
};

如你所见,函数调用运算符只是对传入的对象执行测试转换,以查看它是否是正确的类型,如果是,则返回 true。这个 functor 不携带状态,因此复制可以留给默认构造函数。

第二个示例展示了一个携带状态的基本 functor。你可以从 ID 构建这个 functor,它只会返回 ID 小于给定值的节点。

class CIDFilterFunctor : public base_functor
{
public:
    CIDFilterFunctor( unsigned long filter ) : m_filter( filter ) {}
    CIDFilterFunctor( const CIDFilterFunctor &src ) : m_filter( src.m_filter ) {}
    CIDFilterFunctor &operator=( const CIDFilterFunctor &src )
    {
        if ( this != &src )
            m_filter = src.m_filter;
        return *this;
    }
    virtual bool operator()( const CNodeBase* value ) const
    {
        return value->GetId() < m_filter;
    }
    virtual CIDFilterFunctor *Clone() const
    {
        return new CIDFilterFunctor( *this );
    }
private:
    unsigned long m_filter;
};

这种类型的 functor 是最有趣的。例如,你可以编写一个只返回用户编辑过的对象的 functor,或者只返回在过去一小时内创建的对象。它提供了一种从大型复合体层次结构中提取对象集的新颖方法。

还有一种替代方法可以执行类似的搜索,即使用 find_if STL 算法。我将在文章的后面演示这两种条件迭代的方法。正如你将看到的,我开发的条件迭代器方法具有稍简洁的语法,但代价是迭代器更大。find_if 方法的语法更复杂,但不需要任何额外的实现工作,并且迭代器更小。我将选择权留给你,但我建议如果你预计会大量使用条件迭代器,那么就编写它们,否则就坚持使用 STL 算法方法。使用条件迭代器还有一个最终优势。使用 find_if 方法,你没有 begin 和 end 迭代器,因此无法轻易地将结果馈送到其他 STL 算法。拥有一个真正的 begin 和 end 迭代器(尽管只是基本的前向迭代器)可以让你使用更广泛的 STL 算法。

使用代码

首先,我将向你展示实际迭代器的代码。

浅层迭代器

class functor_iterator
{
    friend class CGenericTree<T>;
public:
    // Normal constructors and destructors
    functor_iterator() : m_iterator(), m_end(), m_functor( NULL ) {}
    functor_iterator( const functor_iterator &src ) :
       m_iterator( src.m_iterator ), m_end( src.m_end ), 
       m_functor( src.m_functor->Clone() ) {}
    functor_iterator &operator=( const functor_iterator &rhs )
    {
        if ( this != &rhs )
        {
            m_iterator = rhs.m_iterator;
            m_end = rhs.m_end;
            m_functor = rhs.m_functor->Clone();
        }
        return *this;
    }
    ~functor_iterator()
    {
        if ( m_functor )
            delete m_functor;
    }
    // Equality operators
    bool operator==( const functor_iterator &rhs ) const
    {
        return m_iterator == rhs.m_iterator;
    }
    bool operator!=( const functor_iterator &rhs ) const
    {
        return m_iterator != rhs.m_iterator;
    }
    // Referencing operators
    _tptr& operator*()
    {
        return *m_iterator;
    }
    _tptr* operator->()
    {
        return &**this;
    }
    // Increment/decrement operators
    typename functor_iterator& operator++()
    {
        ++m_iterator;
        while ( m_iterator != m_end && m_functor && !(*m_functor)( *m_iterator ) )
            ++m_iterator;
        return *this;
    }
    typename functor_iterator operator++(int)
    {
        functor_iterator tmp = *this;
        ++*this;
        return tmp;
    }
private:
    // Private constructor off a container iterator
    explicit functor_iterator(
        const container_iterator &src,
        const container_iterator &end,
        const base_functor &functor ) :
        m_iterator( src ), m_end( end ), m_functor( functor.Clone() )
    {
        while ( m_iterator != m_end && m_functor && !(*m_functor )( *m_iterator ) )
            ++m_iterator;
    }
    // Internal storage is a normal iterator
    container_iterator m_iterator;
    container_iterator m_end;
    const base_functor *m_functor;
};
functor_iterator begin_functor( const base_functor &functor )
{
    return functor_iterator( m_children.begin(), m_children.end(), functor );
}
functor_iterator end_functor( const base_functor &functor )
{
    return functor_iterator( m_children.end(), m_children.end(), functor );
}

深层迭代器

class deep_functor_iterator
{
    friend class CGenericTree<T>;
public:
    // Normal constructors and destructors
    deep_functor_iterator() : m_iterator( NULL ), 
        m_end( NULL ), m_functor( NULL ) {}
    deep_functor_iterator( const deep_functor_iterator &src ) :
        m_iterator( src.m_iterator ), m_end( src.m_end ), 
        m_functor( src.m_functor->Clone() ) {}
    deep_functor_iterator &operator=( const deep_functor_iterator &rhs )
    {
        if ( this != &rhs )
        {
            m_iterator = rhs.m_iterator;
            m_end = rhs.m_end;
            m_functor = rhs.m_functor->Clone();
        }
        return *this;
    }
    ~deep_functor_iterator()
    {
        if ( m_functor )
            delete m_functor;
    }
    // Equality operators
    bool operator==( const deep_functor_iterator &rhs ) const
    {
        return m_iterator == rhs.m_iterator;
    }
    bool operator!=( const deep_functor_iterator &rhs ) const
    {
        return m_iterator != rhs.m_iterator;
    }
    // Referencing operators
    _tptr& operator*()
    {
        return m_iterator;
    }
    _tptr* operator->()
    {
        return &**this;
    }
    // Increment/decrement operators
    typename deep_functor_iterator& operator++()
    {
        increment();
        while ( m_iterator != m_end && m_functor && !(*m_functor)( m_iterator ) )
            increment();
        return *this;
    }
    typename deep_functor_iterator operator++(int)
    {
        deep_functor_iterator tmp = *this;
        ++*this;
        return tmp;
    }
private:
    // Private constructor off a container iterator
    explicit deep_functor_iterator( T *src, T *end, const base_functor &functor ) :
        m_iterator( src ), m_end( end ), m_functor( functor.Clone() )
    {
        while ( m_iterator != m_end && m_functor && !(*m_functor )( m_iterator ) )
            increment();
    }
    // Private increment operator
    void increment()
    {
        if ( m_iterator )
            m_iterator = m_iterator->GetNext();
    }
    // Internal storage is simply a pointer
    T* m_iterator;
    T* m_end;
    const base_functor *m_functor;
};
deep_functor_iterator begin_deep_functor( const base_functor &functor )
{
    return deep_functor_iterator( static_cast<T*>(this), end_val(), functor );
}
deep_functor_iterator end_deep_functor( const base_functor &functor )
{
    return deep_functor_iterator( end_val(), end_val(), functor );
}

为了从 head 迭代整个树,只返回 ID 小于 6 的节点,你可以这样做:

CNodeBase::CIDFilterFunctor fun1( 6 );
CNodeBase::deep_functor_iterator iter_deep_functor = head->begin_deep_functor( fun1 );
for ( ; iter_deep_functor != head->end_deep_functor( fun1 ); ++iter_deep_functor )
    cout << (*iter_deep_functor)->GetId() 
         << " " << (*iter_deep_functor)->GetType() << endl;

使用 STL 算法执行类似操作:

CNodeBase::CIDFilterFunctor fun1( 6 );
CNodebase::deep_iterator iter = find_if( head->begin_deep(), head->end_deep(), fun1 );
for ( ; iter != head->end_deep(); iter = find_if( ++iter, head->end_deep(), fun1 ) )
    cout << (*iter)->GetId() << " " << (*iter)->GetType() << endl;

结论

复合体是一个非常强大的模式,可用于广泛的领域。通过在复合体中编写自定义迭代器,你可以极大地扩展该模式的威力。第一个也是最明显的迭代器实现是深层和浅层迭代器。它们分别迭代整个子树或对象下的单层子节点。可以使深层和浅层迭代器仅返回单个类型的对象。任何使用过复合模式的人可能都遇到过一个经典问题:不断需要执行类型转换才能获取对象,以便对派生类执行操作。使用类型化迭代将所有类型转换都放在基础迭代器中,从而消除了代码中的复杂性。

最后,这些概念可以扩展到允许迭代器接受 functor。functor 决定一个节点是否在特定迭代中返回。Functor 仅仅是具有重载函数调用运算符的类,这意味着它们同时充当对象和函数。使用基于 functor 的迭代器进行条件迭代是解决此问题的一种方法;然而,可以使用 find_if STL 算法解决相同的问题。两者在不同情况下都有其用途,并且由读者自行决定哪种更适合每种情况。

我希望通过过去三篇文章的介绍,我已经让你了解了复合模式的一些复杂性,并让你对自定义迭代器的强大功能有所了解。如果你对自定义迭代器有任何要求,请告诉我,我将考虑撰写一篇关于该主题的文章。

历史

2004 年 10 月 8 日:发布版本 1。

© . All rights reserved.