<< PreviousNext >>

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 to this 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!

Problem

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.

Name: