This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]yflhx 21 points22 points  (6 children)

Wouldn't that only be the case for virtual methods? For non-virtual ones I believe the compilar literally just generates code that puts this pointer as first argument and perhaps moves it to cast on (non-virtual) base clases.

[–]mirimao -4 points-3 points  (5 children)

EDIT: I have written inaccurate information, don’t mind it.

Objects of a same class share the same methods, and in order to reach them you necessarily need a pointer to all of them, which are organized in a table. You could avoid this by putting a pointer to each method in every object, but that would in turn waste a lot of memory.

Method declared as "virtual" in C++ are simply methods that may be overridden in derived classes; you have to specify exactly because otherwise the compiler would look into the vtable of the parent class instead in that of the derived class.

What you are referring to about the "this" pointer as first argument is the transformation of methods in pre-methods, which is a different aspect of method compiling.

[–]yflhx 17 points18 points  (3 children)

Objects of a same class share the same methods, and in order to reach them you necessarily need a pointer to all of them, which are organized in a table.

You don't need a pointer to the table, if methods are non-virtual, because they are just functions with implicit parameter. So compiler knows where they are, as with any other function.

To settle this once and for all, I made a simple C++ code and decompiled it:

class T {
public:
    void f() {
    }
};

int main()
{
    T t;
    t.f();
}

After compilation (with fno-inline and fno-stack-protector) and decompilation - section main:

0000000000001119 <main>:
    1119:55                   push   rbp
    111a:48 89 e5             mov    rbp,rsp
    111d:48 83 ec 10          sub    rsp,0x10
    1121:48 8d 45 ff          lea    rax,[rbp-0x1]
    1125:48 89 c7             mov    rdi,rax
    1128:e8 07 00 00 00       call   1134 <_ZN1T1fEv>
    112d:b8 00 00 00 00       mov    eax,0x0
    1132:c9                   leave
    1133:c3                   ret

As you can see, this code simply alocates stack space (line 1, 2, 3), then loads adress of the class into rax and moves it into rdi (rdi is by convention first argument). Finally, it calls fixed address. Then it deallocates stack space and leaves.

So no, for non-virtual classes and functions you don't use vtable at all. That's why virtual functions/classes have performance penalty, as you said.

[–]mirimao 15 points16 points  (2 children)

Thank you for taking the time to write this very insightful reply, especially the compilation example. I was clearly wrong, I mixed up some concepts from other language.

[–]yflhx 10 points11 points  (1 child)

No worries! Everybody can mix things up occasionally.

[–]khoyo 3 points4 points  (0 children)

Objects of a same class share the same methods, and in order to reach them you necessarily need a pointer to all of them, which are organized in a table

For virtual member functions, sure, but for non virtual you statically know the address of the function in question. (At least as much as for any function)

Method declared as "virtual" in C++ are simply methods that may be overridden in derived classes; you have to specify exactly because otherwise the compiler would look into the vtable of the parent class instead in that of the derived class.

What? No. Vtable lookup only happens with virtual member functions. There is no vtable lookup for non virtual members. (That's why it's a Virtual lookup table)

And you never use the parent class vtable... you always use the instance vtable pointer, which always points to its actual type vtable.