我目前正在设计一个界面(以下示例中为Base
),该界面提供了几种虚拟方法,包括begin()
和end()
。这两个方法简单地返回相应的迭代器,就像在类中的任何其他集合一样。派生类应该实现这些方法并返回它们的迭代器的特定实现。
以下(简化)示例显示了一个派生类,它使用boost::transform_iterator
转换私有内部整数列表。这个实现只是现实中迭代的事物的一个例子。可以是其他东西,迭代器也是如此。
该示例有效,但我有一个问题。 main()
中的对象类型并不隐藏使用的迭代器属于TransformIterator
类型的事实。基类将用于某种插件架构,其中每个插件都是共享库。插件不应该知道使用哪种类型的迭代器,并且应该完全依赖于抽象接口。有没有办法做到这一点?
#include <boost/iterator/transform_iterator.hpp>
#include <iostream>
#include <string>
#include <vector>
template<class Iterator>
class Base
{
public:
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
};
struct toString
{
std::string operator()(int number) const
{
return std::to_string(number);
}
};
typedef boost::transform_iterator<toString, std::vector<int>::iterator> TransformIterator;
class Derived : public Base<TransformIterator>
{
public:
Derived() : ints{132, 3, 6451, 12, 5} {}
TransformIterator begin()
{
return boost::make_transform_iterator(ints.begin(), toString());
}
TransformIterator end()
{
return boost::make_transform_iterator(ints.end(), toString());
}
private:
std::vector<int> ints;
};
int main()
{
Base<TransformIterator>* obj = new Derived();
for(const auto& value : *obj)
{
std::cout << value.size() << std::endl;
}
return 0;
}
更多背景知识:此具体示例基于读取配置文件的接口。目前我只计划为YAML文件提供实现,但其他格式如XML或旧学校INI也是可能的。因此是一个通用的界面。
答案 0 :(得分:3)
我最近在我的一个工作项目中做了类似的事情。我这样做的方法是引入一个抽象迭代器接口和一个访问该接口的迭代器的类。这是一个简化版本:
template <class ValueType>
struct AbstractIterator
{
virtual ValueType& dereference() const = 0;
virtual void increment() = 0;
// and so on...
};
template <class ValueType>
struct ClientIterator : public std::iterator<whatever>
{
std::unique_ptr<AbstractIterator<ValueType>> it;
ClientIterator(std::unique_ptr<AbstractIterator<ValueType>> it) : it(std::move(it)) {}
ValueType& operator* const () { return it->dereference(); }
ClientIterator& operator++ () { it>increment(); return *this; }
// and so on...
};
struct Base
{
typedef ClientIterator<std::string> Iterator;
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
}
struct Derived : Base
{
struct ServerIterator : AbstractIterator<std::string>
{
boost::transform_iterator<toString, std::vector<int>::iterator> it;
virtual std::string& dereference() const override { return *it; }
virtual void increment() override { ++it; }
}
virtual Iterator begin() override { return Iterator({new ServerIterator(something)}); }
virtual Iterator end() override { return Iterator({new ServerIterator(anotherThing)}); }
};
答案 1 :(得分:1)
不是经典的C ++迭代器,没有。它们不适用于多态用途。
您可以做的是为迭代器定义一个抽象基类,然后由每个具体迭代器类型的(模板化)包装器实现。抽象基类只是将所有必需的运算符定义为纯虚拟运算符。缺点是迭代器上的每个操作都需要一个虚函数调用...根据你的用途,这可能会也可能不会成为一个问题(除非你经常使用它们来经常迭代非常大的集合)。
示例:
template <typename T>
class InputIterator<T>
{
public:
virtual T operator*() const = 0;
// Other operators go here
};
template <typename TIterator>
class ConcreteInputIterator final
: public InputIterator<typename std::iterator_traits<TIterator>::value_type>
{
public:
ConcreteInputIterator(TIterator iterator) : m_iterator(iterator) {}
public:
virtual T operator*() const override
{
return *m_iterator;
};
private:
TIterator m_iterator;
};