C++ c+中下行广播期间的内存布局+;

C++ c+中下行广播期间的内存布局+;,c++,C++,当然,对象内部不包含成员函数,只包含数据成员。上面的图表只是为了解释。通常,编译器将类分解为C结构和函数,这些C结构和函数将这个指针作为参数。然后,它以编译C的相同方式编译代码—结构+全局函数。这是编译面向对象代码的常用方法。当然,还有更多的“窍门”,比如虚拟表等等 由于您的成员函数不接触任何成员函数/变量(=使用此指针),因此它工作正常,因为尽管此完全错误,但未使用它 在汇编方面,您的代码如下所示 Parent Child ----------- -----------

当然,对象内部不包含成员函数,只包含数据成员。上面的图表只是为了解释。

通常,编译器将类分解为C结构和函数,这些C结构和函数将
这个
指针作为参数。然后,它以编译C的相同方式编译代码—结构+全局函数。这是编译面向对象代码的常用方法。当然,还有更多的“窍门”,比如虚拟表等等

由于您的成员函数不接触任何成员函数/变量(=使用
指针),因此它工作正常,因为尽管
完全错误,但未使用它

在汇编方面,您的代码如下所示

Parent         Child
-----------     -------------
|         |     |           |
|  sleep  |     |   sleep   |
|         |     | gotoSchool| 
-----------     ------------- 
void gotoSchool(Child*this){cout
但我的问题是为什么它会起作用

因为编译器的实现方式恰好导致了这种行为

不应该这样

如果您的意思是编译器不应该允许这种行为,那么……标准并不要求这样做

它可能,它可以,它确实做到了

工作原理

我手头没有visual studio的源代码,因此我无法确切地告诉您它是如何工作的。但一般来说,成员函数是作为常规函数实现的,除非有一个包含对象地址的额外参数。函数本身在内存中的位置与对象的内存无关.编译器确切地知道函数的代码在哪里

您甚至可以执行
((Child*)nullptr)->gotoSchool();
并观察相同的(未定义的)行为

没有明显的理由说明它不能观察到这种行为

我无法在内存中可视化布局对象


对象的内存布局与函数无关,因为函数从不使用对象的任何内存。

之所以有效,是因为您实际指向的是
子对象。将指针投射到
子对象
不会将其更改为
父对象*
,它只会告诉编译器查看当前的内存指针作为
父对象*
。再次将同一指针投射回
子对象*
不会改变任何东西。如果你“向上投射”到一个不存在的东西,那么底层内存将不正确,但向上投射到你知道它存在的东西会起作用

lower address <---where a pointer to the object points to
    [PTR to VTABLE]
    [data members for parent]
    [data members for child]
higher address
但是,要回答您关于内存布局的问题,通常是:

  void gotoSchool(Child* this){cout<<"chil::gotoSchool";}
   gotoSchool(&parent);

loweraddress它可以工作,因为您实际上不使用实例成员中的任何内容,只需打印一个静态字符串

该函数不是虚拟函数,因此当您调用gotoSchool时,它直接调用它

(使用VS2015进行测试)您也可以在空指针上调用gotoSchool,只要您实际上不尝试引用任何成员,它就可以工作

lower address <---where a pointer to the object points to
    [PTR to VTABLE]
    [data members for parent]
    [data members for child]
higher address
编译器知道pChild是Child类型,并且知道gotoSchool不是virtual,因此它直接调用它,而不管pChild中的值如何

内存布局是什么? 从逻辑上讲,它是空的。 您既没有需要vtable的虚拟成员,也没有成员变量

实际上,它可能包含RTTI的类型信息和/或一些填充字节,但这些都与gotoSchool函数无关

非虚拟功能不是内存布局的一部分!

C++类的实现 有很多更好的解释,但简而言之,成员函数是作为普通函数实现的,带有隐藏的this参数

您的函数在内部是正确的

Child* pChild = (Child*)0;
pChild->gotoSchool();
在您的示例中,
这个
引用了一个父级,但您从未使用过它,所以这无关紧要

未定义的实际实现 您认为它不应该工作,因为它未定义。
但undefined的字面意思是,任何事情都是可能的,并且允许未定义的行为。
我推荐陈雷蒙的这篇文章(以及其他一些文章):

然后,它编译的代码和C++编译的方式一样——结构+全局函数。“嗯……不是。我是说,但不是真的。只有当你在下面调用一个常规的层讨论。嗯,还有其他的行为,特别是如果涉及到其他C++特定的特性,比如模板,但是这种”类型的“。这就是我的意思-函数将this作为函数和成员变量之间的桥梁。@David:即使它是这样传递的,我也不知道它是如何工作的。你可以这样调用它
pChild->gotoSchool(pChild)
并以这种方式接收它
void gotoSchool(Child*mythis){mythis=this;}
。在分配
mythis=this
之前,您可以看到这两个函数都指向同一个地址,因此没有任何区别。如果您想真正了解函数调用的工作原理,您必须学习汇编。但无论如何,即使有分配等,您的成员函数也不会使用
this
。这是它失败的唯一原因正在工作(现在仍然是UB)。一旦函数开始使用
这个
你就会出现更奇怪的行为。不,我的问题与编译器为什么允许或它为什么工作无关,而是它是如何工作的。导致打印语句child::gotoSchool的内存布局是什么。@anurag86我没有源代码,所以我无法确切地告诉你visua是如何工作的l studio可以工作,但我已经扩展到回答这个问题。它可以工作,因为您实际上是指向子对象。不,我不是指向子对象。我只是让编译器相信我指向的是子对象。其次,您显示的布局仅适用于数据成员,在这种情况下,作为成员它并不重要正在访问Action,而不是数据成员。最后,这里不存在VTABLE。啊,我的错,我没有仔细阅读。我以为你是先向父级强制转换,然后再返回。它可以工作,因为你调用的成员函数不访问任何子级da
gotoSchool(Child* this)