0

请考虑以下样板类片段:

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

这些DerivedMember*类型派生自一个公共BaseMember类,并且ObjectA(和类似ObjectB的,ObjectC...)将派生自BaseObject.

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

换句话说,使用如下:

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

调用ObjectA将迭代aa2...

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

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

4

3 回答 3

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

你怎么看?

于 2012-07-09T18:16:03.207 回答
0

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

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

于 2012-07-09T18:16:38.270 回答
0

如果您使用数组来执行此操作,那将是最好的。您当前拥有的代码:

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

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

——里根

于 2012-07-09T18:13:14.480 回答