quantdev2...@yahoo.co.uk wrote:
Hi all,
I have been deling with this kind of code:
class Foo
{
public:
void NonConstMethod()
{}
};
class Bar
{
public:
// [...] (Class simplified)
void NonLogicallyConstMethod() const
{
m_pBar->NonConstMethod();
}
private:
Foo* const m_pBar;
};
Although this is accepted by the compiler, and therefore const-correct,
I often find myself puzzled as to whether this is actually and
logically const-correct.
It just happens that NonLogicallyConstMethod() can invoke a const
method because of the way Bar is associated to Foo i.e. If I used a
class member variable this would not be allowed. The fact that the
pointer itself is const looks like a workaround (not unlike using
<mutable>).
What am I missing?
Thanks,
Quantdev2004
You're not missing anything. Constness is shallow. That is, C++ does
not transfer constness from the pointer to the pointee. (In your case,
m_pBar is always const, but if you removed that const, it would become
const in const methods, though the pointee would not).
There have been many discussions on this NG and others about why this
is or is not a violation of const-correctness. I find the behavior
non-intuitive and think constness should be transferred to the pointee
in these cases and overridden when necessary with mutable-like
declaration, but changing the language would break a good deal of
existing code.
To get the behavior you want, you can do something like this:
template <class T>
class DeepPtr
{
public:
DeepPtr( T *const ptr ) : m_ptr( ptr ) { assert(m_ptr); }
DeepPtr( DeepPtr<T>& ptr ) : m_ptr( ptr.m_ptr ) {}
// Standard access
T* operator->() { return m_ptr; }
T& operator*() { return *m_ptr; }
T& operator[]( ui32 n ) { return m_ptr[ n ]; }
// Make pointee const if pointer is const
T const* operator->() const { return m_ptr; }
T const& operator*() const { return *m_ptr; }
T const& operator[]( ui32 n ) const { return m_ptr[ n ]; }
private:
T * const m_ptr;
// Disabled methods
DeepPtr( const DeepPtr& );
DeepPtr& operator=( const DeepPtr& );
};
struct Foo
{
void NonConst() {};
};
struct Bar
{
Bar( Foo* pFoo ) : m_pFoo( pFoo ) {}
void Const() const { m_pFoo->NonConst(); } // Error!
private:
DeepPtr<Foo> m_pFoo;
};
Unfortunately, the disabled copy constructor and assignment operator
mean that such a pointer cannot be used in a standard container.
Cheers! --M