2010-03-13 78 views
7

我有一個類,其中包括一個std :: list,並希望爲const_iterator和private begin()和end()提供公共begin()和end(),只是普通的迭代器。如何使用公共常量迭代器和私有非常量迭代器提供類似stl的容器?

但是,編譯器看到私有版本並抱怨它是私有的,而不是使用公共const版本。

我知道C++不會在返回類型(在本例中是const_iterator和iterator)上重載,因此它選擇了非const版本,因爲我的對象不是const。

在調用begin()或不重載名稱之前將我的對象轉換爲const的缺點begin有沒有辦法實現這一點?

我會認爲這是一種人們已經解決的已知模式,並希望跟隨如何解決這個問題。

class myObject { 
public: 
    void doSomethingConst() const; 
}; 

class myContainer { 
public: 
    typedef std::list<myObject>::const_iterator const_iterator; 
private: 
    typedef std::list<myObject>::iterator iterator; 

public: 
    const_iterator begin() const { return _data.begin(); } 
    const_iterator end() const { return _data.end(); } 
    void reorder(); 
private: 
    iterator begin() { return _data.begin(); } 
    iterator end() { return _data.end(); } 
private: 
    std::list<myObject> _data; 
}; 

void myFunction(myContainer &container) { 
    myContainer::const_iterator itr = container.begin(); 
    myContainer::const_iterator endItr = container.end(); 
    for (; itr != endItr; ++itr) { 
    const myObject &item = *itr; 
    item.doSomethingConst(); 
    } 
    container.reorder(); // Do something non-const on container itself. 
} 

從編譯器中的錯誤是這樣的:

../../src/example.h:447: error: `std::_List_iterator<myObject> myContainer::begin()' is private 
caller.cpp:2393: error: within this context 
../../src/example.h:450: error: `std::_List_iterator<myObject> myContainer::end()' is private 
caller.cpp:2394: error: within this context 

感謝。

- 威廉

+0

據我看到有在你的代碼沒有繼承,也許你應該糾正「我私下派生一個類」。 – 2010-03-13 19:29:54

+0

糟糕,編輯已經得到了同步的,感謝您指出了這一點,現在是糾正。 – WilliamKF 2010-03-13 19:32:18

+1

如果非const的開始和結束僅對您的容器,你爲什麼要爲他們提供私人的功能呢?爲什麼不直接使用列表迭代器。 – AraK 2010-03-13 19:43:40

回答

4

我認爲你唯一的選擇是重命名私有方法(如果你首先需要它們)。

此外,我相信你應該重命名的typedef:

class MyContainer 
{ 
public: 
    typedef std::list<Object>::const_iterator iterator; 
    typedef iterator const_iterator; 

    const_iterator begin() const; 
    const_iterator end() const; 

private: 
    typedef std::list<Object>::iterator _iterator; 
    _iterator _begin(); 
    _iterator _end(); 
    ... 
}; 

集裝箱都應該既的typedef和iteratorconst_iterator。接受容器的非const實例的泛型函數可能會使用iterator typedef - 即使它不會修改元素。 (例如BOOST_FOREACH

只要const的正確性就會好,因爲如果泛型函數實際上試圖修改對象,那麼真正的迭代器類型(作爲const_iterator)將不會允許它。

作爲測試,下面應該編譯你的容器:

int main() 
{ 
    myContainer m; 
    BOOST_FOREACH(const myObject& o, m) 
    {} 
} 

注意,m是不const的,但我們只是想獲得對包含類型的常量引用,所以這應該是允許。

+0

Arg,在我之前發佈了幾秒鐘! – Potatoswatter 2010-03-13 20:55:26

+0

請參閱http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-ac-identifier – 2010-03-13 21:37:19

+0

@Emile:AFAIK,使用單個下劃線,大小寫字符可以。就我個人而言,我確實不會使用這種風格。 – UncleBens 2010-03-13 21:52:13

5

壞主意,從標準::列表推導(它不是設計給從中導出)。

使用std :: list類型的成員變量。

class myContainer 
{ 
    std::list<myObject> m_data; 
    public: 

    typedef std::list<myObject>::const_iterator myContainer::const_iterator; 
    private: 
    typedef std::list<myObject>::iterator myContainer::iterator; 

    public: 

    myContainer::const_iterator begin() const 
    { 
     return m_data.begin(); 
    } 

    myContainer::const_iterator end() const 
    { 
     return m_data.end(); 
    } 

    private: 
    myContainer::iterator begin() 
    { 
     return m_data.begin(); 
    } 

    myContainer::iterator end() 
    { 
     return m_data.end(); 
    } 
}; 
+0

已更新問題以反映此良好建議,但主要問題仍然存在。似乎唯一的解決辦法是在調用begin()/ end()之前重命名private或static_cast爲const。 – WilliamKF 2010-03-13 19:19:06

4

您需要更改私人開始結束的名稱。編譯器不能僅由返回類型區分

這個工作對我來說:注意_begin _end名

#include <list> 


class myObject {}; 

class myContainer : private std::list<myObject> { 
public: 
    typedef std::list<myObject>::const_iterator const_iterator; 
private: 
    typedef std::list<myObject>::iterator iterator; 

public: 
    myContainer::const_iterator begin() const { 
    return std::list<myObject>::begin(); 
    } 
    myContainer::const_iterator end() const { 
    return std::list<myObject>::end(); 
    } 
private: 
    myContainer::iterator _begin() { 
    return std::list<myObject>::begin(); 
    } 
    myContainer::iterator _end() { 
    return std::list<myObject>::end(); 
    } 
}; 

void myFunction(myContainer &container) { 
    myContainer::const_iterator aItr = container.begin(); 
    myContainer::const_iterator aEndItr = container.end(); 
    for (; aItr != aEndItr; ++aItr) { 
    const myObject &item = *aItr; 
    // Do something const on container's contents. 
    } 
} 

int main(){ 
    myContainer m; 
    myFunction(m); 
} 
+1

雖然名稱會在這裏做的伎倆,你一直有麻煩,如果你想要把你的對象成)的通用功能期待'開頭('和'結束()'... – xtofl 2010-03-13 19:01:28

+0

好像這比唯一可行的選擇等爲每個調用者做static_cast (容器).begin()/ end()。 – WilliamKF 2010-03-13 19:17:54

+0

@Emilie Cormier我不知道。謝謝!。在python中,用一個前導_來命名私有成員是一個常見的習慣用法。 @xtofl,如果這些功能是私有的,任何人,但類本身可以使用它,什麼通用的功能,你在說什麼?一個例子? – fabrizioM 2010-03-14 01:20:08

1

你可能想改變你的方法的MyFunction這個簽名:

void myFunction(const myContainer &container) 

因爲const方法只能在const對象上調用。目前發生的事情是,你正試圖調用一個非const方法,在你的情況下它是私有的。

+0

但是在某些情況下這還不夠,已經更新了測試用例來反映這一點。 – WilliamKF 2010-03-13 19:16:28