C++如何在内存中存储函数和对象?

use*_*663 9 c++ function turbo-c

让我们说我们上课了

class A
{
    int x;
public:
    void sayHi()
    {
        cout<<"Hi";
    }
};

int main()
{
    A *a=NULL;
    a->sayHi();
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将在Turbo C(我测试过的地方)上编译并Hi作为输出打印.

我原以为a是因为崩溃了NULL.sayHi()它说,如果我将功能虚拟化,那就更多了

Abnormal temination(Segmentation fault in gcc) 
Run Code Online (Sandbox Code Playgroud)

我知道很多都是依赖于实现的,但是如果有人可以对任何实现有所启发,或者只是给出一个概述它会非常好.

Die*_*ühl 7

显然,代码具有未定义的行为,即,无论你获得什么是偶然的.也就是说,系统在调用非虚拟成员函数时不需要知道对象:可以根据签名调用它.此外,如果成员函数不需要访问成员,则根本不需要对象,只需运行即可.这是您在代码打印一些输出时观察到的.然而,这是否是系统的实现方式尚未定义,也就是说,没有任何说明它有效.

当调用虚函数类型系统时,开始查看与该对象关联的类型信息记录.在NULL指针上调用虚函数时,不存在此类信息,并且尝试访问它可能会导致某种崩溃.尽管如此,它并不是必须的,但它适用于大多数系统.

顺便说一句,main() 总是回来int.


eno*_*ram 6

在C++中,类的方法不存储在该类的实例中.this除了程序员指定的参数之外,它们只是一些透明地接受指针的"特殊"函数.

在您的情况下,该sayHi()方法不引用任何类字段,因此,从不遵循this指针(即NULL).

不过,毫无疑问,这仍然是未定义的行为.当您调用此程序时,您的程序可能会选择将讨厌的电子邮件发送到您的联系人列表.在这个特定的例子中,它做了最糟糕的事情,似乎工作.

virtual,因为我回答了这个问题方法的情况下增加了,但我不会改进我的答案,因为它是由别人的答案包括在内.


mar*_*rko 5

一般来说,从类实例化的对象的布局如下:

* - v_ptr  ---> *  pTypeInfo
|               |- pVirtualFuncA
|               |- pVirtualFuncB
|- MemberVariableA
|- MemberVariableB
Run Code Online (Sandbox Code Playgroud)

v_ptr是指向 v 表的指针 - 其中包含对象的虚拟函数地址和 RTTI 数据。没有虚函数的类没有 v 表,相应的对象也没有v_ptr.

在上面的示例中,class A没有虚拟方法,因此没有 v 表。这意味着 to call 的实现sayHi()可以在编译时确定并且是不变的。

编译器生成的代码将隐式this指针设置为a,然后跳转到 的开头sayHi()。由于该实现不需要对象的内容,因此当指针存在时它就可以工作这一事实是NULL一个令人愉快的巧合。

如果要进行sayHi()虚拟化,编译器无法确定在编译时调用的实现,因此会生成在 v 表中查找函数地址并调用它的代码。在您的示例中, ais NULL,编译器读取 address 的内容0,导致中止。