如果您要设计界面,我会继续将它们放在一个容器中,但为用户提供只允许访问公共客户端部分的自定义迭代器。 boost::iterator_adaptor
使编写这种迭代器变得容易。
#include "Client.hpp"
#include <list>
#include <boost/iterator_adaptor.hpp>
class ClientList {
public:
class iterator;
class const_iterator;
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
private:
struct InternalData {
//...
};
struct ClientAndData {
Client client;
InternalData data;
};
typedef std::list<ClientAndData> internal_list_type;
internal_list_type m_clients;
friend class iterator;
friend class const_iterator;
};
class ClientList::iterator
: public boost::iterator_adaptor<
ClientList::iterator, // Derived type for CRTP
ClientList::internal_list_type::iterator // Iter type to encapsulate
Client > // Data type to expose
{
private:
explicit iterator(const base_type& base_iter)
: iterator_adaptor(base_iter) {}
Client& dereference() const { return base()->client; }
friend class ClientList;
// Allow boost to call dereference():
friend class boost::iterator_core_access;
};
class ClientList::const_iterator
: public boost::iterator_adaptor<
ClientList::const_iterator,
ClientList::internal_list_type::const_iterator
const Client >
{
public:
const_iterator(const iterator& iter)
: iterator_adaptor(iter.base()) {}
private:
explicit const_iterator(const base_type& base_iter)
: iterator_adaptor(base_iter) {}
const Client& dereference() const { return base()->client; }
friend class ClientList;
friend class boost::iterator_core_access;
};
inline ClientList::iterator ClientList::begin()
{ return iterator(m_clients.begin()); }
inline ClientList::const_iterator ClientList::begin() const
{ return const_iterator(m_clients.begin()); }
inline ClientList::iterator ClientList::end()
{ return iterator(m_clients.end()); }
inline ClientList::const_iterator ClientList::end() const
{ return const_iterator(m_clients.end()); }
或者,如果您的代码的用户应该只获得const Client&
引用,那么您只需要一种迭代器类型,它看起来很像const_iterator
上面的类。
这里没有Client
对象的复制;用户获得对私有列表中相同对象的引用。
这确实在迭代器类型中公开了一个公共base()
成员函数,可以被讨厌的人用来获取InternalData
. 但是任何知道或发现的人base()
也应该知道或意识到他们不应该使用它。但是,如果这让您担心,您可以iterator_adaptor
私下继承,然后再次手动将其所有公共成员设为 base()
公共成员。或者(可能更容易),将所有内容设为InternalData
私有或受保护,然后friend
将使用它的类设为您身边的类。