2009-12-11 45 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>與您的容器。