Iterator对类成员的引用,简单且优选可重用

时间:2012-07-09 18:06:40

标签: c++ iterator

请考虑以下样板类片段:

class ObjectA : public BaseObject
{
    DerivedMemberA a, a2, a3;
    DerivedMemberB b;
    DerivedMemberC c;
    // ...
};  

DerivedMember*类型来自常见的BaseMember类,而ObjectA(以及类似的ObjectBObjectC ...)将来自BaseObject

现在我想实现一个迭代器,它将在公共BaseObject接口中,并且会迭代对派生类成员的引用(如BaseMember&)。

换句话说,使用就像:

BaseObject& b = someObject;
for (BaseObject::iterator it = b.begin(); it != b.end(); ++it)
{
    BaseMember& m = *it;
    // ...
}
调用ObjectA

会迭代aa2 ......

解决此问题的最佳方法是什么?最好还避免对迭代器进行子类化。是否有可以在那里重用的现成迭代器类或模板?

我正在考虑实现一个虚拟成员函数,该函数将获取变量的数字“索引”并使用switch返回适当的引用;然后从索引保持迭代器中调用该成员。

3 个答案:

答案 0 :(得分:0)

如果你使用数组做到这一点最好。您目前拥有的代码:

DerivedMemberA a, a2, a3;
DerivedMemberB b, b2;
DerivedMemberC c, c2;

几乎没有真正的结构。为什么不使用DerivedMemberA对象数组而不是使用3个DerivedMemberA对象? B和C也一样。

-Reagan

答案 1 :(得分:0)

快速&肮脏的概念验证:

template <class Source, class Type>
class MyIterator : public std::iterator<std::input_iterator_tag, Type>
{
    typedef Type* (Source::*getter_method)(int n);

    Source& _inst;
    getter_method _getter;
    int _index;
    bool _end;
    Type* _curr_val;

public:
    MyIterator(Source& instance, getter_method method, bool end = false)
        : _inst(instance), _getter(method), _index(0), _end(end)
    {
        if (!end)
            ++*this;
    }

    void operator++()
    {
        assert(!_end);
        _curr_val = (_inst.*_getter)(_index++);

        if (!_curr_val)
            _end = true;
    }

    bool operator!=(MyIterator rhs)
    {
        return _end != rhs._end;
    }

    Type& operator*()
    {
        assert(!_end);

        return *_curr_val;
    }
};

使用如下实现的对象:

class BaseObject
{
protected:
    virtual BaseMember* iterator_getter(int n) = 0;

public:
    typedef MyIterator<BaseObject, BaseMember> iterator;

    iterator begin()
    {
        return iterator(*this, &BaseObject::iterator_getter);
    }

    iterator end()
    {
        return iterator(*this, &BaseObject::iterator_getter, true);
    }
};

和派生对象如:

class ObjectA : public BaseObject
{
    // ...
protected:
    virtual BaseMember* iterator_getter(int n)
    {
        BaseMember* ret;

        switch (n)
        {
            case 0:
                ret = &a;
                break;
            case 1:
                ret = &a2;
                break;
            case 2:
                ret = &a3;
                break;
            // ...
            default:
                ret = 0;
        }

        return ret;
    }

您怎么看?

答案 2 :(得分:0)

C ++没有任何内省概念,因此基类绝对无法知道派生类中定义了哪些成员。

您可以做的最好的事情是在每个派生类中创建一个迭代自己成员的虚函数。