类成员和成员函数内存位置 [英] Class members and member functions memory location

查看:372
本文介绍了类成员和成员函数内存位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里是一个简单的C ++类:

  class A 
{
public:
explicit a():m_a(0){}
explicit A(int a)m_a(a){}
int getA()const {return m_a; }
void setA(int a){m_a = a; }

private:
int m_a;
}

这是我所知道的:




  • 当你声明一个类实例的一个对象时,内存被分配给该对象。分配的内存相当于其成员的内存总计。所以在我的情况下,类A的所有成员函数都存储在 sizeof(A)= sizeof(int)= sizeof(m_a)




这是我不要 strong>知道:



成员函数存储在哪里,它们是如何存储的?让我们假设一个 int 例如存储在4个字节;我可以想象RAM内存布局有4个连续的单元格,每个存储的int的一部分。我怎么能想象这个布局的功能?(这听起来很傻,但我想象函数必须有一个地方在内存中,因为你可以有一个指针指向它们)。函数指令如何存储和在哪里存储?我的第一感觉是函数和函数指令存储在程序可执行文件(及其动态或静态库),但如果这是真的,当你创建一个函数指针时会发生什么? AFAIK函数指针指向RAM存储器中的位置,它们可以指向程序二进制文件中的位置吗?如果是,这是如何工作的?



任何人都可以向我解释这是如何工作的,指出如果我知道是对还是错?

解决方案

首先,您需要了解链接器以及什么是可执行文件(通常在< a href =http://en.wikipedia.org/wiki/Virtual_memory =nofollow>虚拟内存)和地址空间& 流程。在Linux上,请参阅 ELF execve(2) syscall。另请参阅 Levine's Linkers&装载工具书



会员功能可以是虚拟或普通功能。




  • 一个简单的(非 virtual )成员函数就像一个C函数(除了它具有 this 作为隐式的,经常是第一个参数)。例如,您的 getA 方法像下面的C函数(对象外部,例如在代码段的二进制可执行文件):

      int C $ getA A * thisptr)const {return thisptr-> m_a; } 

    然后想象编译器正在翻译 p-& c

    http://en.wikipedia.org/wiki/Virtual_function =nofollow>虚拟成员函数通常通过 vtable 虚拟方法表)。具有一些虚拟成员函数(包括析构函数)的对象通常作为其第一(隐式)成员字段指向这样的表(由编译器在别处生成)的指针。您的 A类没有任何虚拟方法,但想象如果它有一个额外的 virtual void print(std :: ostream&); code>方法,那么您的类A 将具有与

    相同的布局

      struct A $ {
    struct A $ virtualmethodtable * _vptr;
    int m_a;
    };

    ,虚拟表可能是

      struct A $ virtualmethodtable {
    void(* print $ fun)(struct A $ *,std :: ostream *);
    };

    (因此添加其他虚拟函数意味着只需在 vtable ;
    然后像 p-> print(std :: cout); 的调用将被翻译成类似
    p - > _vptr.print $ fun(p,&std :: cout); ...此外,编译器将生成各种虚方法表(每个类一个) / p>




NB:多重或虚拟继承更复杂。 b
$ b

在这两种情况下,成员函数不会在对象中占用任何额外的空间。如果它是非虚拟的,它只是一个普通的函数(在代码段)。如果它是虚拟的,它在虚拟方法表中共享一个槽。



NB。如果你用最近的GCC(即 g ++ )编译,你可以传递它。 -fdump-tree-all 标志:它将产生数百个转储文件,显示部分转储的文本形式 - 编译器的一些内部表示,你可以检查一个寻呼机(例如 less )或一个文本编辑器。您还可以使用 MELT 或查看使用 g ++ -S -verbose生成的汇编代码-asm -O1 ....


Here be a simple C++ class:

class A
{
public:
    explicit A() : m_a(0) { }
    explicit A(int a) m_a(a) { }
    int getA() const { return m_a; }
    void setA(int a) { m_a = a; }

private:
    int m_a;
}

This is what I know so far:

  • when you declare an object of a class instance, memory gets allocated for that object. The allocated memory is equivalent to the memory of its members summed up. So in my case sizeof(A) = sizeof(int) = sizeof(m_a)
  • all member functions of class A are stored somewhere in memory and all instances of class A use the same member functions.

This is what I don't know:

Where are member functions stored and how are they actually stored? Let's say that an int for example is stored on 4 bytes; i can imagine the RAM memory layout with 4 contiguous cells each storing a part of that int. How can I imagine this layout for a function?(this could sound silly, but I imagine functions must have a place in memory because you can have a pointer point to them). Also how and where are function instructions stored? My first perception was that functions and function instructions are stored in the program executable(and its dynamic or static libraries) but if this is true what happens when you create a function pointer? AFAIK function pointers point to locations in RAM memory, can they point to locations in program binaries? If yes, how does this work?

Can anyone explain to me how this works and point out if what I know is right or wrong?

解决方案

First, you need to understand the role of the linker and what are executables (usually executed in virtual memory) and address spaces & processes. On Linux, read about ELF and the execve(2) syscall. Read also Levine's Linkers & Loaders book.

Member functions can be virtual or plain functions.

  • A plain (non virtual) member function is just like a C function (except that it has this as an implicit, often first, parameter). For example your getA method is implemented like the following C function (outside of the object, e.g. in the code segment of the binary executable) :

    int C$getA(A*thisptr) const { return thisptr->m_a; }
    

    then imagine that the compiler is translating p->getA() into C$getA(p)

  • A virtual member function is generally implemented thru a vtable (virtual method table). An object with some virtual member functions (including destructor) has generally as its first (implicit) member field a pointer to such a table (generated elsewhere by the compiler). Your class A don't have any virtual method, but imagine if it had an additional virtual void print(std::ostream&); method, then your class A would have the same layout as

    struct A$ {
       struct A$virtualmethodtable* _vptr;
       int m_a;
    };
    

    and the virtual table might be

    struct A$virtualmethodtable {
      void (*print$fun) (struct A$*, std::ostream*);
    };
    

    (so adding other virtual functions means simply adding slot inside that vtable); and then a call like p->print(std::cout); would be translated almost like p->_vptr.print$fun(p,&std::cout); ... In addition, the compiler would generate as constant tables various virtual method tables (one per class).

NB: things are more complex with multiple or virtual inheritance.

In both cases, member functions don't eat any additional space in the object. If it is non-virtual, it is just a plain function (in the code segment). If it is virtual, it shares a slot in the virtual method table.

NB. If you compile with a recent GCC (i.e. with g++) you could pass it e.g. the -fdump-tree-all flag: it will produce hundreds of dump files showing partly -in a dumped textual form- some internal representations of the compiler, which you could inspect with a pager (e.g. less) or a textual editor. You could also use MELT or look at the assembly code produced with g++ -S -fverbose-asm -O1 ....

这篇关于类成员和成员函数内存位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆