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

时间:2012-05-01 06:32:01

标签: c++ casting

  

可能重复:
  Regular cast vs. static_cast vs. dynamic_cast
  Undefined, unspecified and implementation-defined behavior

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

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

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

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

并显示“NewClass Test”。我不明白它是如何键入任何指向NewClass的指针的,并且仍然有效。

提前致谢!

4 个答案:

答案 0 :(得分:3)

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

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

结果未定义,但在大多数情况下您应该预期会产生不良副作用,并且应该不惜一切代价避免重新解释数据。

在这种情况下,编译器可能会插入结果,因为它知道它们。此外,没有出现任何错误,因为在这种情况下没有实际依赖于对象的地址或状态:Test()不依赖于this的state / data / members / dynamic methods / vtable

如果你要将std::string的成员添加到NewClass并打印出来......那么你可以期待事情比现在更快爆发:)

如果危险不明显:这是极其危险的转换 - int*支持的所有数据都被重新解释为NewClass*,以及它的所有内部存储器和结构(例如vtable和magic cookies)会相应地重新解释。不久之后你的程序会出现错误,要么超出分配结束时的读数(int*),要么将int视为完全不相关的类型 - 在这种情况下,请考虑具有vtable或数据的类的内存布局,例如向std::string添加一些NewClass,以及读取和写入这些成员。

答案 1 :(得分:1)

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

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

你有一个空数据结构(即没有数据),但仍然附加了一个方法 - Test()。

因此,当您声明指向某个东西的指针(在您的护理中为int)时,指针仅指向某个内存。现在你有一个新的Int(),因此ptr指向的内存是整数大小。

由于你的类没有数据,并且它没有内部结构,需要内存中的对象以特定方式(例如虚拟方法)在内存中布局,你可以认为你指向任何东西或者事实没什么,因而可以称呼你的方法。

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

   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(); 
    } 

看看它打印出来的东西。

如果你理解这一点 - 试着阅读你的编译器如何列出对象。这将告诉您很多关于您的平台上存在此行为的原因。

答案 2 :(得分:0)

这似乎是未定义的行为。但是,您总是可以在c ++中使用reinterpret-cast来执行此操作。重新使用reinterpret_cast运算符可能很容易导致不安全。除非所需的转换本质上是低级别的,否则您应该使用其他一个转换运算符。 reinterpret_cast运算符可用于转换,例如char *到int *,或One_class *到Unrelated_class *,这些转换本质上是不安全的。

答案 3 :(得分:0)

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

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

也就是说,行为是不明确的,这意味着在任何一种情况下都会发生任何事情。