Disclaimer: I will use IA-32 assembly for samples.
Typically, each object is a structure residing block of memory allocated either on heap (via new
call) or on stacK (basically, by moving esp
to reserve memory for it). After memory is allocated, pointer is passed to object constructor for initialization (note that ctor can be inlined, this way no call
is made).
Usually, each object having virtual methods has a pointer a table of virtual methods (usually called VMT or vtable which stores pointers to functions. When you are calling virtual method, address of this method is got and it is called. Code looks like this
mov ecx, [this]
mov ebx, vtable
push [arg2]
push [arg1]
call [ebx + OFFSET_foo] ; this->foo(arg1, arg2);
Note that in this sample I've shown that this
is passed via ecx and args are passed via stack in right-to-left order. This is thiscall
convention, used in VC++ by default, e.g. Other compilers may employ other conventions, as it is shown in article linked.
For non-virtual calls no need for table lookup. So code looks like
mov ecx, [this]
push [args]
push [arg1]
call bar ; this->bar(arg1, arg2)
This is why non-virtual methods can be executed a bit faster - its address is well known, so compiler can start decoding their code before encountering call
opcode.
In some calling conventions (e.g. fastcall
) arguments are passed via registers which can be faster in some cases.
In most calling conventions result iss returned via eax
register if it fits this registers, via FPU stack, if this is floating point or via stack otherwise.
If you want to learn more about translating C++ code to assembly, I'd recommend to
try to make your compiler generate assembly listing during compilation (usually -S key; it can be set in VC++ project settings as well);
try to disassemble code e.g. using excellent IDA disassembler. There's free version of it. It helps a lot by providing symbolic names for local variables, recognizing library functions etc.
Good luck!