Re: Shall I use mutable or const_cast or remove const?
Martin B. wrote:
DeMarcus wrote:
Hi,
I have some trouble understanding the true meaning of const.
Please consider this example.
class Store
{
public:
void add( int* item ) { /* ... */ }
};
class Item
{
public:
Item( int item ) : item_(item) {}
void giveToStore( Store& store ) const { store.add( &item_ ); }
private:
int item_;
};
Now, this gives me "invalid conversion from 'const int*' to 'int*'" when
exposing item_ in store.add( &item_ ). What's the way of thinking here?
(....)
4. Redesign according to C++ Coding Standards by Sutter & Alexandrescu,
Item 11 - Hide information. Basically it says; "Don't expose internal
information from an entity that provides an abstraction.". However, my
real problem (illustrated with Item) is a kind of wrapper similar to
boost::shared_ptr and I need something like boost::shared_ptr::get().
Therefore I'm clueless about finding an alternative design.
A const member function must not only not modify the object, it must
also not expose anything that could be used to directly modify the object.
With shared_ptr, get() can return the non-const pointer since shared_ptr
holds the pointer, not the object itself. (Plus one might note that if
you use that pointer to do a delete, things come crashing down.)
With your example, modifying the item pointer to item_ always results in
modifying the Item object, so you either give out a const pointer or the
member function is indeed not const. _If_ giveToStore should be const,
then Store::add should take a const int* -- _if_ Store is allowed to
modify item, the giveToStore should not be const.
br,
Martin
Thanks all of you for great input! Here's a more detailed version of my
structure.
class NumberCruncher // Previously Store, and it may change values
{
public:
template<typename T>
void addItem( T* item ) { /* Do number crunching on item */ }
};
class ItemContainerInterface // Previously just Item
{
public:
// This is the const in question.
virtual addMe( NumberCruncher& ) const = 0;
virtual removeMe( NumberCruncher& ) const = 0;
};
template<typename T>
class ItemContainer : public ItemContainerInterface
{
public:
virtual addMe( NumberCruncher& nc ) const
{ nc.addItem( &item_ ); }
virtual removeMe( NumberCruncher& nc ) const
{ nc.removeItem( &item_ ); }
private:
T item_;
};
template<typename T>
class ItemSharedPtrContainer : public ItemContainerInterface
{
public:
virtual addMe( NumberCruncher& nc ) const
{ nc.addItem( item_.get() ); }
virtual removeMe( NumberCruncher& nc ) const
{ nc.removeItem( &item_.get() ); }
private:
boost::shared_ptr<T> item_;
};
class DataSet
{
public:
void addAllToNC( NumberCruncher& nc ) const
{
auto end = dataSet_.end();
for( auto i = dataSet_.begin; i != end; ++i )
(*i)->addMe( nc );
}
private:
std::vector<ItemContainerInterface*> dataSet_;
};
int main()
{
NumberCruncher nc;
DataSet d;
int anInt = 63;
boost::shared_ptr<Circle> sp( new Circle( 12 ) );
d.addSomeItem( 35 );
d.addSomeItem( sp );
d.addSomeItem( 47.11 );
d.addSomeItem( boost::ref( anInt ) );
d.addAllToNC( nc );
}
I've left out some functions here and there but the general message is
that the previous Store (now NumberCruncher) can alter the data in the
pointer it gets. Not directly with addItem() but at a later time.
The problem is that the item container can hold both shared pointers and
the type itself. So sometimes it's an ItemContainer and sometimes it's
an ItemValue. In both cases it is a kind of owner of the value, so maybe
I have to remove const from ItemContainerInterface::addMe() because the
value may be changed at a later time by NumberCruncher.
The difficulty is that ItemSharedPtrContainer only holds a pointer and
therefore addMe() could be const. But ItemContainer holds the value and
therefore it cannot be const. Shall I just remove const to support both
containers or is there a way to refactor the design?
Thanks!
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]