Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Mark B goes over the fundamental considerations, but note that you can do something similar in pure C++. Consider:</p> <pre><code>struct Data { }; class ConstImage { protected: const Data *const_data; public: ConstImage (const Data *cd) : const_data(cd) { } int getFoo() const { return const_data-&gt;getFoo(); } }; class Image : public ConstImage { protected: Data *data() { return const_cast&lt;Data *&gt;(const_data); } public: Image(Data *d) : const_data(d) { } void frob() { data()-&gt;frob(); } }; </code></pre> <p>Instead of using <code>const Image *</code>, use <code>ConstImage *</code>, and there you go. You could also simply define a static function pseudo-constructor:</p> <pre><code>const Image *Image::newConstImage(const Data *d) { return new Image(const_cast&lt;Data*&gt;(d)); } </code></pre> <p>This, of course, relies on the programmer to ensure that there aren't any <code>const</code> functions which might somehow mutate the pointed-to <code>Data</code>'s state.</p> <p>You can also combine these techniques:</p> <pre><code>class Image { protected: const Data *const_data; Data *data() { return const_cast&lt;Data *&gt;(const_data); } public: void frob() { data()-&gt;frob(); } int getFoo() const { return const_data-&gt;getFoo(); } Image(Data *d) : const_data(d) { } static const Image *newConst(const Data *cd) { return new Image(const_cast&lt;Data *&gt;(cd)); } }; </code></pre> <p>This gets the best of both worlds; since <code>data()</code> is a non-const member, you have static checking for mutation of the pointed-to value. You also, however, have a const constructor, and can directly cast between <code>Image *</code> and <code>const Image *</code> (ie, you can remove the constness if you know it is safe).</p> <p>You can also abstract away the separation of pointers further:</p> <pre><code>template&lt;typename T&gt; class ConstPropPointer { private: T *ptr; public: ConstPropPointer(T *ptr_) : ptr(ptr_) { } T &amp;operator*() { return *ptr; } const T &amp;operator*() const { return *ptr; } T *operator-&gt;() { return ptr; } const T *operator-&gt;() const { return ptr; } }; class Image { protected: ConstPropPointer&lt;Data&gt; data; public: void frob() { data-&gt;frob(); } int getFoo() const { return data-&gt;getFoo(); } Image(Data *d) : data(d) { } static const Image *newConst(const Data *cd) { return new Image(const_cast&lt;Data *&gt;(cd)); } }; </code></pre> <p>Now, if <code>this</code> is const, <code>data</code> becomes const, propagating that into <code>*data</code> as well. Good enough for you? :)</p> <p>I suppose the final answer is probably this: In order for a const constructor to be useful and safe, we'd need something like the <code>ConstPropPointer</code> you see there built into the language. Const constructors would then be allowed to assign from <code>const T *</code> to <code>constprop T *</code>. This is more complex than it sounds - for example, how does this interact with template classes such as <code>vector</code>?</p> <p>So, this is a somewhat complex change, but the problem doesn't seem to come up all that much. More importantly, there's a simple workaround here (the <code>ConstPropPointer</code> can be librarized, and the static pseudo-constructor is simple enough to add). So the C++ committee probably passed it over for more important things, if it was even proposed at all.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload