我想设计一个类Foo
,它存储不同类型的各种数据,并通过它们返回迭代器。它应该是通用的,因此Foo
的用户不知道数据的存储方式(Foo
可能正在使用std::set
或std::vector
或其他任何内容。
我很想写一个这样的界面:
class Foo {
class FooImpl;
FooImpl* impl_;
public:
const Iterator<std::string>& GetStrings() const;
const Iterator<int>& GetInts() const;
};
其中Iterator
就像这样(就像.NET中的迭代器一样):
template<class T>
class Iterator {
public:
const T& Value() const = 0;
bool Done() const = 0;
void Next() = 0;
};
但是我知道这种迭代器在C ++中不是标准的,并且最好像STL一样使用迭代器,所以你可以在它们上使用STL算法。
我该怎么做? (我是否需要iterator_traits
?)
答案 0 :(得分:4)
您是否理解为什么STL选择将迭代器实现细节放在头文件中? JIT框架能够跨编译单元内联,但C ++只能在编译单元中内联。在内联时,推进序列的速度要快得多,函数调用的成本实际上主要是遍历数据结构。
如果您真的想隐藏实施细节,请继续。你可以创建一个STL兼容的迭代器来实现operator ++和operator!=和operator-&gt;就受保护的虚拟功能而言,您提到的Next,Done和Value将是不错的名称。只是希望以较低的性能为封装付费。
答案 1 :(得分:1)
使用typedef返回boost::iterator_range
。例如(不要介意名字),
class Container
{
typedef std::vector<int> Collection;
public:
typedef boost::iterator_range<Collection::iterator> CollectionRange;
typedef Collection::iterator CollectionIterator;
Range range() const {
return make_iterator_range(collection_.begin(), collection_.end());
}
private:
Collection collection_;
};
用户代码为
Container c;
// ...
FOREACH(int i, c.range()) { //... }
Container::Range r = c.range();
for(Container::iterator j = r.begin(); j!= r.end(); j++) { // ... }
这不是通用的,但同样的想法可以与模板一起使用。
答案 2 :(得分:1)
带有迭代器的c ++类必须提供至少两个函数,如果它们必须使用std库
iterator begin() //returns an iterator at starting pos
iterator end() //returns an iterator one past end or just invald
迭代器必须重载增量运算符,equals和*
iterator operator++()
iterator operator==()//make sure that an invalid iterator equals end()
T& operator*()
您可以使用迭代器类来包装内部存储的迭代器,以确保用户仅限于这些方法。
template <typename T> iter
{
iter(T::iterator& intern)
T::value_type& operator*(){return *intern}
iter operator++(){return iter(++intern);}
bool operator==(iter const& other)const{return intern == other.intern;}
}
其中T是你的容器的类型。(这个类是不完整的,我可能混淆了一些东西)
答案 3 :(得分:1)
这几乎看起来你正在尝试创建与容器无关的代码,除非你正在编写一个只能用迭代器操作的算法,否则它(通常)不是一个好主意。 (参见Scott Myers Effective STL第2项:注意与容器无关的代码的错觉)
问题是大多数标准容器不提供重叠功能。如果您正在为特定容器编写代码,请假设您正在为该容器编写代码。不要试图让它与容器无关。
答案 4 :(得分:-1)
要满足头文件中未提及特定容器(vector,set,...)并且用户能够遍历所有字符串的要求,请使用访问者模式< / strong>即可。当然,缺点是用户将无法在字符串上使用STL算法。
// foo.h
class StringVisitor {
public:
void accept(const std::string& str) {
std::cout << str << std::endl;
}
};
class Foo {
class Impl;
Impl* impl_;
public:
Foo();
~Foo();
void VisitStrings(StringVisitor v) const;
};
// foo.cc
class Foo::Impl {
typedef std::vector<std::string> StringContainer;
StringContainer str_;
public:
Impl() {
str_.push_back("a");
str_.push_back("b");
}
void VisitStrings(StringVisitor v) const {
for(StringContainer::const_iterator it = str_.begin();
it != str_.end(); ++it){
v.accept(*it);
}
}
};
Foo::Foo() : impl_(new Impl()) {}
Foo::~Foo() {delete impl_;}
void Foo::VisitStrings(StringVisitor v) const {
impl_->VisitStrings(v);
}
// main.cc
int main() {
Foo foo;
foo.VisitStrings(StringVisitor());
return 0;
}