C ++类型将int *转换为类

C++ type casting int * to class

本问题已经有最佳答案,请猛点这里访问。

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

我面临一个奇怪的问题。在下面的代码片段中,我定义了一个类

1
2
3
4
5
6
7
8
   class NewClass
   {
      public:
         void Test()
         {
             cout<<"NewClass Test"<<endl;
         }
   };

在我的main()方法中,我写到:

1
2
3
4
5
6
        void main()
        {
           int *ptr = new int();
           NewClass *n = ((NewClass *)ptr);
           n->Test();
        }

显示"NewClass测试"。我不理解如何将任何指针类型转换为newclass,并使其仍然工作。

事先谢谢!


这是工作中的静态调度。在这种情况下,this确实是不必要的(例如,NewClass::Test()中没有使用或依赖它)。

强制转换为NewClass *n = ((NewClass *)ptr);是按地址进行的类型转换,在此上下文中没有类型检查。换句话说,您没有在任何地方创建一个新的NewClass实例,您只是将int*指定地址的内存作为NewClass*处理。这是一个应该避免的危险转变。如果需要通过丢失类型安全性的地址(如void*)对对象进行漏斗访问,请始终确保两端都知道发送和接收的内容。幸运的是,擦除类型安全性变得越来越不常见。

结果是未定义的,但是在大多数情况下,您应该预料到不良的副作用,并且应该避免以任何代价重新解释数据。

在这种情况下,编译器可能会插入结果,因为它知道它们。此外,在这种情况下,由于没有实际依赖对象的地址或状态,因此没有显示错误:Test()不依赖this的状态/数据/成员/动态方法/vtable。

如果您要将std::strings等成员添加到NewClass并打印这些成员…你可以期待事情比现在更迅速地爆发:)

如果危险不明显:这是一个极其危险的转换——所有由int*支持的数据都被重新解释为NewClass*,所有内部存储器和结构(如vtables和magic cookies)都被重新解释。在程序SEG错误出现之前不会花很长时间,要么是通过读取超出分配结束(int*),要么是将int视为完全不相关的类型——在这种情况下,考虑具有vtable或数据的类的内存布局,例如将一些std::string添加到NewClass中,然后读写到那些成员。


在你开始思考一个复杂的为什么它不应该起作用之前,考虑一个简单的场景来帮助你尝试和想象它。

类是一个附加了方法的数据结构。当然,编译器是不同的,所以行为可以被认为是未定义的,但暂时忽略这一点。

您有一个空的数据结构(即没有数据),但仍然有一个附加到它的方法-test()。

因此,当您声明指向某个对象的指针(您关心的int)时,该指针只指向一些内存。现在您有了一个新的int(),因为ptr指向的内存大小是整数。

由于您的类没有数据,而且它也没有内部结构,这就要求内存中的对象以特定的方式(例如虚拟方法)在内存中布局,因此您可以考虑指向任何对象或实际上没有对象,因此可以调用您的方法。

创建一个这样的类,看看会发生什么:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   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();
    }

看看它能打印出什么。

如果你理解了这一点,试着读读你的编译器,了解它是如何布置对象的。这将告诉您许多关于平台上存在此行为的原因。


您的方法未声明为虚方法。这意味着对它的调用完全由编译器解决,就像它是一个非方法函数一样,只是您必须在一个正式的NewClass变量上调用它。

编译器可能会使用虚拟方法表来调度对虚拟方法的调用,如果该方法是虚拟的,那么最终可能会以垃圾代替VMT,然后开始崩溃。

也就是说,行为是未定义的,意味着任何事情都可能发生。


这似乎是未定义的行为。但是,您可以总是使用EDCOX1 17来做这件事,在C++中滥用RealTytCube运算符可以很容易地不安全。除非所需的转换本质上是低级的,否则您应该使用其他转换运算符之一。reinterpret_cast运算符可用于char*到int*等转换,或用于一个_class*到不相关的_class*的转换,这些转换本质上是不安全的。