Answer to Avoiding const_cast
Think about the way pointers behave in a const class. If
we declare a pointer int *a
and try to use it in a const
class, how would it look?
At first one may think it would be const int *a
, but it is
actually int * const a
, which means that the pointer itself
is const, not whatever it is pointing to. This actually makes
sense, since the const
in C++ by default means binary constant.
If we can get hold of a non-const pointer to our object, we can actually exploit this to store the non-const pointer for later use when we are a const object. For example:
class Hack { public: Hack *noConst; int data; void a() { noConst = this; } void b() const { noConst->data = 8; } };
Here we can see that as long as the user first runs a
, then b
can bypass the const check and modify the object anyway. The problem
here is that it requires the user of the class to call a
first.
Is there any other function that is better suited for this?
We can use the constructor! We know that the constructor is called
first, so if we set noConst
there, it will always be executed before
anything else might need the noConst
variable. Even better, in the
constructor the this
pointer is never const
!
Using this, we can write our Lazy
class like this:
class Lazy { public: Lazy() : noConst(this), loaded(false) {} int value() const { load(); return v; } int size() const { load(); return s; } protected: // load the contents of this class. virtual void loadMe() = 0; // Values lazily loaded somehow. int v, s; private: Lazy *noConst; bool loaded; void load() const { if (loaded) return; noConst->loadMe(); noConst->loaded = true; } }
However, this has some problems:
- If you use a pointer, the default copy and assignment will copy the pointer
value as well, so you will end up with a
noCopy
pointer that does not point tothis
anymore. - You can use a reference as well, in that case you will not get a default implementation of the copy or the assignment functions.
- It is as bad as a
const_cast
!
Comments
New comment
You can use GitHub flavored markdown here. Parsed by Parsedown, which does not support all of GitHub's features. For example, specifying the language of code listings is not supported.