2009-12-11 46 views
0

我目前正在一个项目中,我想定义一个通用的'集合'接口,可能以不同的方式实现。集合接口应该指定集合具有按值返回迭代器的方法。使用类,包装指针我想出了以下(大大简化):C++类层次结构集合提供迭代器

Collection.h

class Collection 
{ 
    CollectionBase *d_base; 
public: 
    Collection(CollectionBase *base); 

    Iterator begin() const; 
}; 

inline Iterator Collection::begin() const 
{ 
    return d_base->begin(); 
} 

CollectionBase.h

class CollectionBase 
{ 
public: 
    virtual Iterator begin() const = 0; 
    virtual Iterator end() const = 0; 
}; 

Iterator.h

class Iterator 
{ 
    IteratorBase *d_base; 
public: 
    bool operator!=(Iterator const &other) const; 
}; 

inline bool Iterator::operator!=(Iterator const &other) const 
{ 
    return d_base->operator!=(*other.d_base); 
} 

IteratorBase.h

class IteratorBase 
{ 
public: 
    virtual bool operator!=(IteratorBase const &other) const = 0; 
}; 

使用这种设计,收集的不同实现从CollectionBase派生,并可以通过返回一个Iterator一个包装一些具体实施IteratorBase返回其自定义的迭代器。

到目前为止,一切都很好。我目前正试图弄清楚如何实施operator!=Iterator将呼叫转接到IteratorBase,但运营商应该如何在那里实施?一种简单的方法是将IteratorBase引用转换为IteratorBase实现中的适当类型,然后执行IteratorBase实现的具体比较。这假设你会玩得很好,但不会传递两种不同类型的迭代器。

另一种方法是执行某种类型的检查,检查迭代器是否属于同一类型。我相信这个检查必须在运行时进行,考虑到这是一个迭代器,我宁愿在operator!=中执行昂贵的运行时类型检查。

我在这里错过了更好的解决方案吗?也许有更好的替代课程设计(目前的设计是从我在C++课程中学到的东西改编而来)?你会如何处理这个问题?

编辑:给大家指点我的STL容器:我知道它们的存在。但是,我不能在所有情况下使用这些数据,因为我需要处理的数据量通常很大。这里的想法是实现一个简单的容器,它使用磁盘作为存储而不是内存。

+2

哦gawd ... C++已经*有*容器和迭代器的概念。如果你与之一起玩,你将能够真正使用第三方代码!不要重新发明轮子。特别是当你的车轮会变成越野车时,效率低下且难以使用。 – jalf 2009-12-11 11:40:39

+0

“一个使用磁盘作为存储的简单容器”我们已经有了 - 它们被称为文件。迭代器对于文件的接口并不是那么明智,但如果你需要它们,标准也提供了这一点。 – 2009-12-11 12:05:32

回答

2

如果您想为迭代器使用继承,我建议您使用与STL的begin()/end()不同的方法。例如,从.NET框架看IEnumerator。(MSDN documentation

基类可以是这样的:

class CollectionBase 
{ 
    // ... 
    virtual IteratorBase* createIterator() const = 0; 
}; 

class IteratorBase 
{ 
public: 
    virtual bool isEnd() const = 0; 
    virtual void next() const = 0; 
}; 

// usage: 
for (std::auto_ptr<IteratorBase> it = collection.createIterator(); !it->isEnd(); it->next) 
    { 
    // do something 
    } 

如果你想留在begin()/end(),您可以使用dynamic_cast检查是否有一个正确的类型:

class MyIteratorBaseImpl 
{ 
public: 
    virtual bool operator!=(IteratorBase const &other) const 
    { 
     MyIteratorBaseImpl * other2 = dynamic_cast<MyIteratorBaseImpl*>(&other); 
     if (!other2) 
      return false; // other is not of our type 

     // now you can compare to other2 
    } 
} 
+1

如果你的性能真的很重要,你可以在debug build中使用dynamic_cast,在零售版本中使用static cast,如下所示:assert(dynamic_cast (&other)== static_cast (&other)); – denisenkom 2009-12-11 12:31:53

+0

迭代器有一种方式可以在C++中工作,即begin()/ end()。枚举有一种方法可以在Java中使用,它是hasMoreElements()和nextElement()。有一种方法IEnumerators预计在.NET中工作,它是isEnd()/ next()。 只要OP没有声明他想模仿Java或.NET,但要求一个“普通的”C++问题,我发现推荐非C++概念最好是误导性的。 – DevSolar 2010-02-22 10:25:59

0

我可以建议你在迭代器中添加一个虚拟的'entiy-id'函数,并且在运算符中!=检查this-> entity_id()和other.entity_id()(my example,'position'function is such'entity- ID'功能)。

4

这不是你应该使用C++的方式。我强烈建议你调查一下标准库容器类,比如std :: vector和std :: map,以及模板的使用。继承应始终是最后手段的设计工具。

1

模仿STL做容器的方式。这样,就有可能例如使用<algorithm>与您的容器。