22

Suppose we have a class:

class Foo
{
private:
    int a;
public:
    void func()
    {
       a = 0;
       printf("In Func\n");
    }
}

int main()
{
    Foo *foo = new Foo();
    foo->func();
    return 0;
}

When the object of the class Foo is created and initialized, I understand that integer a will take up 4 bytes of memory. How is the function stored? What happens in memory / stack /registers / with the program counter when calling foo->func()?

shaveenk
  • 1,983
  • 7
  • 25
  • 37

3 Answers3

28

The short answer: It will be stored in the text or code section of the binary only once irrespective of the number of instances of the class created.

The functions are not stored separately anywhere for each instance of a class. They are treated the same way as any other non-member function would be. The only difference is that the compiler actually adds an extra parameter to the function,which is a pointer of the class type. For example the compiler will generate the function prototype like this:

void func(Foo* this);

(Note that this may not be the final signature. The final signature can be much more cryptic depending on various factors including the compiler)

Any reference to a member variable will be replaced by

this-><member> //for your ex. a=0 translates to this->a = 0;

So the line foo->func(); roughly translates to:

  1. Push the value of Foo* on to the stack. #Compiler dependent
  2. call func which will cause the instruction pointer to jump to the offset of func in the executable #architecture dependent Read this and this
  3. Func will pop the value from stack. Any further reference to a member variable would be preceded by dereferencing of this value
bashrc
  • 4,725
  • 1
  • 22
  • 49
18

Your function is not virtual, it is thus statically called : the compiler inserts a jump to the code segment corresponding to your function. No additional memory is used per instance.

Were your function virtual, your instance would carry a vpointer, which would be dereferenced to find its class' vtable, which would then be indexed to find the function pointer to be called, and finally jump there. The additional cost is thus one vtable per class (probably the size of one function pointer, times the number of virtuals functions of your class), and one pointer per instance.

Note that this is a common implementation of virtual calls, but is in no way enforced by the standard, so it could actually not be implemented like that at all but your chances are quite good. The compiler can also often bypass the virtual call system altogether if it has knowledge of the static type of your instance at compile time.

Quentin
  • 62,093
  • 7
  • 131
  • 191
  • "the compiler inserts a jump to the code segment". Where is this jump information stored? – shaveenk Jul 01 '14 at 07:54
  • 1
    @shaveenk Directly at the calling site, i.e. another part of the code segment. For a static call it gets hardcoded, so you just end up with a plain goto 0xSomewhere; in the assembly (after some parameters tweaking) – Quentin Jul 01 '14 at 07:57
5

Member functions are just like regular functions, they are stored in the "code" or "text" section. There is one thing special with (non-static) member functions, and that is the "hidden" this argument that is passed along to function. So in your case, the address in foo will be passed to func.

Exactly how that argument is passed, and what happens to registers and stack is defined by the ABI (Application Binary Interface), and varies from processor to processor. There is no strict definition for this, unless you tell us what the combination of compiler, OS and processor is being used (and assuming that information is then publicly available - not all compiler/OS vendors will tell this very clearly). As an example, x86-64 will use RCX for this on WIndows, and RDI on Linux, and the call instruction will automatically push the return address onto the stack. On an ARM processor [in Linux, but I think the same applies in Windows, I just have never looked at that], R0 is used for the this pointer, and the BX instruction used for the call, which as part of itself stores lr with the pc of the instruction to return to. lr then has to be saved [probably on the stack] in func, since it calls printf.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227