15

Do interfaces (polymorphic class solely with pure virtual functions) have a vtable? Since interfaces do not implement a polymorphic function themself and cant be directly constructed there would be no need for the linker to place a vtable. Is that so? Im especially concerned about the MSVC compiler.

John Dibling
  • 99,718
  • 31
  • 186
  • 324
Sebastian Hoffmann
  • 11,127
  • 7
  • 49
  • 77
  • A *very* important note is the `declspec(novtable)` feature in MSVC: it allows interfaces, especially COM ones, to omit the vtable. This has some interesting and significant implications when it comes to inheritance (forces single inheritance, but causes the final object to only have a single table providing more polymorphism than otherwise). – ssube Jun 25 '12 at 20:07

3 Answers3

9

Yes, they do. And there are a number of good reasons for that.

The first good reason is that even pure virtual methods have implementation. Either implicit or explicit. It is relatively easy to pull off a trick calling a pure virtual function, so you can basically provide a definition for one of yours, call it and see what happens. For that reason, there should be a virtual table in a first place.

There is another reason for putting a virtual table into a base class even if all of its methods are pure virtual and there are no other data members though. When polymorphism is used, a pointer to a base class is passed all around the program. In order to call a virtual method, compiler/runtime should figure out the relative offset of the virtual table from the base pointer. If C++ had no multiple inheritance, one could assume a zero offset from the abstract base class (for example), in which case it would have been possible not to have a vtable there (but we still need it due to reason #1). But since there is a multiple inheritance involved, a trick ala "vtable is there at 0 offset" won't work because there could be two or three vtables depending on a number (and type) of base classes.

There could be other reasons I haven't though of as well.

Hope it helps.

  • Good argumentation! Haven't thought of that. – Luchian Grigore Jun 25 '12 at 20:02
  • 2
    The trick you refer to, is it one that doesn't either required the pure virtual function to be defined (under _odr_ rules) or otherwise cause undefined behavior because I was not aware of any such trick? – CB Bailey Jun 25 '12 at 20:15
  • 3
    I'm not convinced by your first reason. I'm pretty sure the only ways to call a pure virtual function are (a) call it non-virtually, which doesn't use the vtable, or (b) invoke undefined behaviour by calling it from the constructor/destructor of a partially constructed object, which isn't required to call it at all. Or do you know another trick that I don't? – Mike Seymour Jun 25 '12 at 20:26
  • @MikeSeymour: I guess it depends on how well defined is undefined. I am not a standard junkie. In practice, it may depend on implementation but is very well defined. Another trick would be - go figure out offset of the method in vtable and call it directly. But vtable must be there, either having address 0x0 for a function/method or address, address of user-supplied definition or default implementation. –  Jun 25 '12 at 20:38
6

From a purely C++ point of view it's an academic question. Virtual functions don't have to be implemented with vtables, if they are there is no portable way to get at them.

If you're particular concerned about the MSVC compiler you might want to decorate your interfaces with __declspec(novtable).

(In general, in common implementations, an abstract class may need a vtable, e.g.:

struct Base {
    Base();
    virtual void f() {}
    virtual void g() = 0;
};

void h(Base& b) {
    b.f(); // Call f on a Base that is not (yet) a Derived
           // vtable for Base required
}

Base::Base() {
    h(*this);
}

struct Derived : Base {
    void g() {}
};

int main() {
    Derived d;
}

)

CB Bailey
  • 755,051
  • 104
  • 632
  • 656
  • I want to see how they can be implemented not using virtual tables or any other approach where at least sizeof(void *) have to be added to a class serving as a "starting point"... –  Jun 25 '12 at 20:02
  • 1
    @VladLazarenko: I think it's almost universally accepted that a vptr/vtable based solution is optimal but impractial implementations such as storing a map of address to dynamic type information of some form are at least theoretically possible. – CB Bailey Jun 25 '12 at 20:12
  • You got the point. I think what I mean is that no matter how you call it, you will need at least some starting point to access it, be that a pointer to vtable, a pointer to hash with addresses or hash itself to some global hash with maps to function pointers. –  Jun 25 '12 at 20:53
2

The vtable is not necessary, but rarely optimized out. MSVC provides the __declspec(novtable) extension, which tells the compiler explicitly that the vtable can be removed. In the absence of that, the compiler would have to check itself that the vtable is not used. This is not exceptionally hard, but still far from trivial. And since it doesn't provide real speed benefits in regular code, the check is not implemented in any compiler I know.

MSalters
  • 173,980
  • 10
  • 155
  • 350