Reputation: 681
I'm writing the iterator classes for a custom container (some hash map class), let's call this container Map
.
For a couple of reasons it seems handy to derive iterator
from const_iterator
and I already did this in some other custom container (an array class), which works great, so I want to stick to this pattern.
But now that leads to the following problem (which is quite general/abstract, I'm sorry):
Whatever const_iterator
's critical data member is (it might be a Map
reference, or a pointer to Map::Elements
, many ways are possible), it needs to be non-const so both const_iterator
and the derived iterator
can utilize it meaningfully in their methods.
But how can this non-const data member, in a proper way, be initialized when dealing with a const Map
object (e.g. calling the method const_iterator Map::Begin( void ) const
)?
To illustrate my question bit, I wrote some example code that solves the problem by using const_cast which, I suppose, is bad style:
#include <vector>
template< typename K, typename T >
class Map
{
public:
class const_iterator
{
public:
const_iterator( Map const & a_Map, int a_Index ) :
m_Index( a_Index ),
m_Map( const_cast< Map & >( a_Map ) ) // Note the use of const_cast
{
}
private:
Map & m_Map;
int m_Index;
};
class iterator : public const_iterator
{
public:
T & operator * ( void )
{
return m_Map.mElements[ m_Index ];
}
};
public:
const_iterator Begin( void ) const { return const_iterator( *this, 0 ); }
iterator Begin( void ) { return iterator( *this, 0 ); }
private:
std::vector< T > m_Elements;
};
Upvotes: 2
Views: 1055
Reputation:
When I played with this in the past, I convinced myself that inheritance wasn't a good idea. While iterator
and const_iterator
might share a lot of code, they don't really share much in their interface.
Instead, I used templates to get the code reuse, so that iterator
and const_iterator
are just two versions of the same template. Provide an appropriate implicit conversion operator.
But if you insist on the inheritance model, and don't want your iterator to have its own non-const reference (i.e. its constructor initializes both its non-const version and the base class's const version), then const_cast
is the only real option, I think.
Upvotes: 2