存储在内存中的对象的函数在哪里
Where are functions of an object stored in memory?
假设我们有一个类:
class Foo
{
private:
int a;
public:
void func()
{
a = 0;
printf("In Funcn");
}
}
int main()
{
Foo *foo = new Foo();
foo->func();
return 0;
}
当Foo类的对象被创建和初始化时,我知道整数a将占用4个字节的内存。函数是如何存储的?调用foo->func((时,内存/堆栈/寄存器/程序计数器中会发生什么?
简短的答案是:无论创建的类的实例数量如何,它都将只存储在二进制文件的文本或代码部分一次。
对于类的每个实例,函数不会单独存储在任何位置。它们的处理方式与其他任何非成员函数相同。唯一的区别是编译器实际上向函数添加了一个额外的参数,即类类型的指针。例如,编译器将生成如下的函数原型:
void func(Foo* this);
(请注意,这可能不是最终签名。最终签名可能更神秘,这取决于包括编译器在内的各种因素(
对成员变量的任何引用都将被取代
this-><member> //for your ex. a=0 translates to this->a = 0;
因此,行foo->func((;大致翻译为:
- 将Foo*的值推送到堆栈中#编译器相关
- 调用func,这将导致指令指针跳转到可执行文件中func的偏移量#依赖于体系结构读取this和this
- Func将从堆栈中弹出该值。对成员变量的任何进一步引用之前都将取消对该值的引用
您的函数不是虚拟的,因此它是静态调用的:编译器插入到与您的函数对应的代码段的跳转。每个实例不使用额外的内存。
如果你的函数是虚拟的,你的实例会携带一个vpointer,它会被取消引用以找到它的类"vtable",然后它会被索引以找到要调用的函数指针,最后跳到那里。因此,额外的成本是每个类一个vtable(可能是一个函数指针的大小,乘以类的虚拟函数的数量(,每个实例一个指针。
请注意,这是虚拟调用的常见实现,但标准并没有强制执行,因此它实际上根本不可能像那样实现,但您的机会非常大。如果编译器在编译时知道实例的静态类型,那么它通常也可以完全绕过虚拟调用系统。
成员函数就像常规函数一样,它们存储在"代码"或"文本"部分。(非静态(成员函数有一点特别,那就是传递给函数的"隐藏"this
参数。因此,在您的情况下,foo
中的地址将传递给func
。
该参数的确切传递方式,以及寄存器和堆栈的情况由ABI(应用程序二进制接口(定义,并且因处理器而异。对此没有严格的定义,除非你告诉我们正在使用编译器、操作系统和处理器的组合(并假设信息是公开的——并不是所有的编译器/操作系统供应商都会非常清楚地告诉我们(。例如,x86-64将在WIndows上使用RCX
作为this
,在Linux上使用RDI
,调用指令将自动将返回地址推送到堆栈上。在ARM处理器上[在Linux中,但我认为Windows中也是如此,我只是从未看过],R0用于this
指针,BX指令用于调用,作为其本身的一部分,它将lr
与要返回的指令的pc
存储在一起。然后,lr
必须保存在func
中[可能在堆栈上],因为它调用printf
。
- 堆分配对象中的堆栈对象在 c++ 中在哪里分配?
- 当线程处理不同的类时,应该在哪里声明条件变量、互斥对象
- 组件对象模型 (COM):IMalloc::Alloc 在哪里分配内存?
- 当我们在C++中创建类的对象时,为成员函数分配的内存在哪里?
- 工厂方法创建的对象应该在哪里删除?
- 为什么类型转换对象不会更改其地址?有关对象类型的信息存储在哪里?
- 分配以下对象属性在哪里
- 我的共享内存对象保存在哪里
- 返回对象存储在哪里
- 在基本的GUI编程中,在哪里声明对象和方法
- 我创建的c++istream对象和cin之间的区别在哪里,它在库中的可见位置在哪里
- 我在哪里可以找到一些 c++ 中的好例子来研究面向对象的概念
- 在c++中,全局作用域中只允许"表达式"初始化全局对象.我在哪里可以在标准中找到这个
- 存储的临时对象在哪里
- 静态对象的非静态成员分配在哪里
- 在哪里声明从Qt SIGNAL/SLOT返回的对象
- 在堆栈上创建对象时分配的内存在哪里
- 异常对象在哪里有其空间、堆或堆栈,以及如何在不同的类中访问它
- 在C++中,std::cin 对象定义在哪里
- 在哪里为QMainWindow声明某些Qt对象:在头文件或构造函数中