Question

I have some problem with understanding the code below. Why am I able to call c() function?

#include <iostream>
#include <list>


using namespace std;

class A
{};

class B : public A
{
 public:
  void c() { cout << "c: B" << ++x << endl; }   
  int x;
};

int main(void) {
  class A *a = new A();
  static_cast<B*>(a)->c();

  return 0;
}

The ouptut is:

constr A
c: B1
Was it helpful?

Solution

It's because undefined behavior can have unexpected results, including appearing to work.

Anything can happen, this is undefined behavior. What probably actually does happen is that B::c() uses the location where B::x would have been stored in a B instance, right after1 the A subobject. And it overwrites memory belonging to some other object. In your case, the value was previously 0 and became 1, but it could have been whatever value was put there by the real owner of that location.

(1) If the compiler implements the empty base class optimization, B::x and the B::A subobject could actually overlap.


If you're asking why the compiler doesn't prevent it, it's because you've overridden type checking by using a static_cast. Of all the casts, only dynamic_cast pays any attention to the true type of the object, and even that is easy to break.

You're composing two operations which are well-defined in a very unsafe way.

  • The compiler can't stop you from casting an A* to a B*, even when it knows there is no B object, because that B* is perfectly useful for the solitary purpose of casting back again.
  • And it can't stop you from using a B* to access B members.

The problem is that you used this "fake" B* for something other than casting back to its true type.

OTHER TIPS

dynamic_cast can provide information about success or failure (if you have at least one virtual function which I assume that your real program would have), but static_cast cannot. static_cast doesn't use Run Time Type Identification. There are legitimate reasons for casting, but you need to follow the rules in order to avoid undefined behavior.

Prefer dynamic cast over static cast when downcasting. Of course I have no idea why someone would write a program with inheritance and not one single virtual function (unless it is just a simple example for demonstrating a problem), but maybe there is a usecase or a reason for doing that. http://en.cppreference.com/w/cpp/language/dynamic_cast

If you absolutely must use static_cast, then you need to follow the rules about when it makes sense to do so. Unfortunately static_cast will not provide you with exception or failure notification so it must be used cautiously. http://en.cppreference.com/w/cpp/language/static_cast

2) If new_type is a pointer or reference to some class D and the type of expression is a pointer or reference to its non-virtual base B, static_cast performs a downcast. Such static_cast makes no runtime checks to ensure that the object's runtime type is actually D, and may only be used safely if this precondition is guaranteed by other means, such as when implementing static polymorphism. Safe downcast may be done with dynamic_cast.

To address your question about why your example appears to work, allow me to quote the ANSI std.

1.3.24 [defns.undefined] undefined behavior behavior for which this International Standard imposes no requirements [ Note: Undefined behavior may be expected when this International Standard omits any explicit definition of behavior or when a program uses an erroneous construct or erroneous data. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed. — end note ]

Avoid casts at any time - it usually means that something is going wrong.

In you example your are trying to convert an object to have more powers that it processes.

It is like saying to somebody this vehicle is a lorry and point to a car.

It will end in tears when a Trebant arrives not a wagon

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top