5

Possible Duplicate:
Regular cast vs. static_cast vs. dynamic_cast
Undefined, unspecified and implementation-defined behavior

I am facing a strange issue. In the following snippet I define a class

   class NewClass
   {
      public:
         void Test()
         {
             cout<<"NewClass Test"<<endl;
         }
   };

In my main() method, I write:

        void main()
        {
           int *ptr = new int();
           NewClass *n = ((NewClass *)ptr);
           n->Test();
        }

and it displays "NewClass Test". I dont understand how its possible to type-cast any pointer to NewClass and still have it working.

Thanks in advance!

Community
  • 1
  • 1
GeeKay
  • 53
  • 1
  • 5

4 Answers4

3

That's static dispatch at work. this is really unnecessary in this case (e.g. it is not used or relied upon within NewClass::Test()).

Casting as NewClass *n = ((NewClass *)ptr); is type conversion by address, and there is no type checking in this context. In other words, you're not creating a new NewClass instance anywhere, you are simply treating the memory at the address specified by the int* as a NewClass*. This is a dangerous conversion which should be avoided. In the event you need to funnel an object through an address where there type safety is lost (e.g. void*), always be sure both ends know what is sent and received. Fortunately, erasing type safety is becoming less common.

The results are undefined, but you should expect bad side effects in most cases and you should avoid reinterpreting data as such at all costs.

In this case, the compiler likely inserted the results because it knew them. Furthermore, no error was exhibited because there is no actual dependence on the address or state of the object in this case: Test() does not rely on the state/data/members/dynamic methods/vtable of this.

If you were to add members such as std::strings to NewClass and print those as well... you can expect things to blow up sooner than they do now :)

In the event the dangers are not evident: This is an extrememly dangerous conversion -- all the data backed by the int* is being reinterpreted as NewClass*, and all of its internal memory and structure (e.g. vtables and magic cookies) are reinterpreted accordingly. It won't take long before your program seg faults, either by reading beyond the end of the allocation (int*), or by treating an int as a completely unrelated type -- in this case, consider the memory layout of a class with a vtable or data, such as adding some std::strings to the NewClass, and reading from and writing to those members.

justin
  • 104,054
  • 14
  • 179
  • 226
  • thanks. I was wondering where the NewClass object was instantiated in my code. I understand the bit about no type-checking and also understand its a bad programming practice to cast anything to just anything. Inputs appreciated. Cheers! – GeeKay May 01 '12 at 06:43
  • @GeeKay that's what i meant with "type conversion by address". there is no `NewClass` -- you're simply treating an `int*` as `NewClass*` :) you will see a `NewClass` is neither created or destroyed in this case. (adding to answer…) – justin May 01 '12 at 06:45
1

Before you start thinking about a complex why it shouldn't work consider a simple scenario to help you try and picture it.

A class is a data structure with methods attached to it. Of course ever compiler is different so the behaviour could be consider undefined, but ignore this for the time being.

You have an empty data structure (ie no data), but there is still a method attached to it - Test().

So when you declare a pointer to something (int in your care) the pointer is only pointing to some memory. Now you have a new Int(), thereforr the memory pointed to by ptr is integer sized.

Since your class has no data it and it has no internal structures that necessitate that the object in memory is laid out in memory in a particular way (virtual methods for example), you can consider that you are pointing to anything or in fact nothing, and thus can call your method.

Create a class like this and see what happens:

   class NewClass 
   { 
      private int i;
      public: 
         void Test() 
         { 
             cout<<"NewClass Test i="<< i << endl; 
         } 
   };

    void main() 
    { 
       int *ptr = new int();
       *ptr =  10; 
       NewClass *n = ((NewClass *)ptr); 
       n->Test(); 
    } 

See what it prints out.

If you understand this - try and read up on your compiler on how it lays out objects. This will tell you lots about why this behaviour exists on your platform.

Preet Sangha
  • 64,563
  • 18
  • 145
  • 216
0

This seems like undefined behaviour . However you can always do this using reinterpret-cast in c++ Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired conversion is inherently low-level, you should use one of the other cast operators. The reinterpret_cast operator can be used for conversions such as char* to int*, or One_class* to Unrelated_class*, which are inherently unsafe.

Invictus
  • 4,028
  • 10
  • 50
  • 80
0

Your method is not declared as virtual. It means that the call to it is completely resolved by the compiler, the same as it would be a non-method function, except that you have to call it on a variable that is formally a NewClass which you are.

Your compiler probably uses virtual method tables to dispatch calls to virtual methods and if the method was virtual, you would probably end up with garbage in place of the VMT and then you would start getting crashes.

That said, the behavior is undefined meaning that anything can happen in either case.

Jirka Hanika
  • 13,301
  • 3
  • 46
  • 75