Search code examples
c++castingdynamic-cast

dynamic_cast a non-const ref to a const ref. cppreference.com's explanation seems odd


I was refreshing my memory on the various types of casting available and came across the following on cppreference.com (http://en.cppreference.com/w/cpp/language/dynamic_cast):

1) If the type of expression is the exactly new_type or a less cv-qualified version of new_type, the result is expression.

Referring to the structure

dynamic_cast < new_type > ( expression )

I interpreted that to mean that, for example, attempting a dynamic_cast of a non-const reference to a const reference of the same type would actually yield the non-const reference and therefore allow me to call its non-const members, which is the opposite of what I'd expect. I wrote the following noddy piece of code to check that out:

#include<iostream>

class Base
{
  int value;
public:
  Base():value(0){};

  virtual void ShowVal() const
  {
    printf("Value is %d\n", value);
  }

  virtual void SetVal(int val)
  {
    value = val;
  }

};

int main ()
{
  Base b;
  Base& rB = b;

  b.ShowVal();

  (dynamic_cast<const Base&>(rB)).SetVal(2); //fails where (dynamic_cast<Base&>(rB)).SetVal(2); is obviously fine.

  b.ShowVal();
}

As I'd have expected anyway, this doesn't compile and I get the error

blah.cpp:28:3: error: member function 'SetVal' not viable: 'this' argument has type 'const Base', but function is not marked const
(dynamic_cast<const Base&>(rB)).SetVal(2);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I suppose the question I'm meandering towards is: Have I misunderstood the rule above? And if so, what is it actually saying and is there a similarly basic example that demonstrates it?

Thanks. (In the meantime I'm going to read it again, and if I realise I've misread it then I'll quickly delete this question and commence facepalming...)


Solution

  • It's not so obvious from the way that's written, but the conversion still takes place. It just means that the object you get from the conversion (the pointer or reference) is the same as the one denoted by expression. The cast expression is of const type though because that's what you converted it to.

    Here's what it looks like in the C++11 standard:

    If the type of v is the same as T, or it is the same as T except that the class object type in T is more cv-qualified than the class object type in v, the result is v (converted if necessary).

    Note the "converted if necessary".

    You might wonder why it even bothers saying that the result is expression? For most dynamic_casts, the result is not expression. Consider casting from a pointer to base class to a pointer to derived class. You don't get the same pointer out of it. Instead, you get a pointer to the derived subobject.