0

So I know that in c++ virtual methods are for each class stored in table and each instance has a pointer that points to that table. So my question how subclass table looks like. I will provide an assembler directive:

vtable for Derived:
    .long   0
    .long   _typeinfo for Derived
    .long   _Derived::set()
    .globl  _vtable for Base
    .section    .rdata$vtable for Base,"dr"
    .linkonce same_size
    .align 4

So, from here I can see that Derived has one virtual method which is set(), but the part which bugs me is vtable for Base. Does Derived vptr holds pointer to Base vptr or is it stored inside of Derived's vtable. I've noticed that in code compiler just stores vtable at 0 address of object, once in Base constructor and once in Derived. Why isn't vtable overwritten?

P.S. I don't really understand directives

EDIT:

class Base{
   virtual void print() {
       printf("Base");
   }
}

class Derived : Base{
   virtual void print(){
       printf("Derived");
   }
}
6
  • Maybe it is overwritten. But if base stores first and derived second then it's overwritten with the correct value. Commented Mar 26, 2020 at 22:21
  • 1
    @ErikEidt at least in g++ code, the constructor writes the vtable pointer into the object. So base constructor writes base vtable into the object and then the derived constructor overwrites that with the derived vtable. Commented Mar 26, 2020 at 22:22
  • 1
    I don't know much about directives, but I think that .globl is just a matter of symbol visibility; vtable for Derived is only made of the tree first .long in terms of stored information. Commented Mar 26, 2020 at 22:24
  • 1
    It was pretty clear to me that's what he asked: "compiler just stores vtable at 0 address of object, once in Base constructor and once in Derived. Why isn't vtable overwritten?". He has seen that both constructors write to the same location. I explained how that works. Commented Mar 26, 2020 at 22:26
  • @Jester Yes you understood what I asked, sorry for bad formating the question. Thank you for clarification. Commented Mar 26, 2020 at 22:29

1 Answer 1

5

Simple answer is: it depends on the compiler. The standard does not specify how this should be implemented, only how it should behave.

In practice, implementations tend to simply have a derived vtable which begins with the same structure as the base vtable, than appends the derived class methods on the end (that is to say new methods in the derived class, not overrides).

The vtable pointer just points the the beginning of the whole table. If the object is being accessed through a base pointer type, then no one should ever look beyond the end of the base class methods.

If the pointer is of the derived type, then the same pointer will allow access further down the table to virtual methods declared in the derived class.

ADDENDUM: Multiple Inheritance

Multiple inheritance follows the same basic concepts, but quickly becomes complex for obvious reasons. But there's one important feature to bear in mind.

A multiply derived class has one vtable pointer for each of its base classes, pointing to different vtables or different locations in the same vtable (implementation dependent).

But it's important to remember it's one per immediate base class per object.

Thus if you had a multiply derived class with one int of data and three immediate base classes, the size of each object would actually be 16 bytes (on a 32-bit system; more on 64-bit). 4 for the int and four each for each of the vtable pointers. Plus, of course, the sizes of each of the base classes themselves.

That means that in C++, interfaces are not cheap. (Obviously there are no true interfaces in C++, but a base class with no data and only pure virtual methods emulates it.) Each such interface costs the size of a pointer per object.

In languages like C# and Java, where interfaces are part of the language, there is a slightly different mechanism whereby all interfaces are routed through a single vtable pointer. This is slightly slower, but means only one vtable pointer per object, however many interfaces are implemented.

I'd still follow an interface style approach in C++ for design reasons, but always be aware of this additional overhead.

(And none of this even touches on virtual inheritance.)

Sign up to request clarification or add additional context in comments.

4 Comments

I think this makes sense, so basically if I had 3 different derived classes, each class would have Base vtable appended with it's own table and I assume that with each further subclass, that subclass would just append it's own table?
For multiple inheritance, there's a few more twists involved. Yet still a compiler implementation detail, and not something that should be exploited in the code (it'd be very precarious code, and not portable).
@Eljay God yes! Multiple inheritance is horrible, though I've added an important caveat to my answer.
@AntonioAntolcic: related: How do objects work in x86 at the assembly level? shows some real compiler-generated asm for x86 for some of the simplest cases of accessing data members and making virtual functions. I think you already know that much, but possibly future readers would benefit. Nice summary of inheritance, Jasper, +1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.