1

first: I read somewhere that the mechanism of virtual functions is undefined. i.e. that mean that every compiler can impelement it differently. But, every text that I found about virtual function mechanisn talk about VTBL and VPTR.

Is there another virtual function mechanism implementations? Could you bring some examples?

second: What is the differences between VTBL implementation in different languages?

Constantin
  • 8,721
  • 13
  • 75
  • 126
asaf app
  • 384
  • 2
  • 3
  • 12

3 Answers3

1

One popular alternative is inline caching that, I think, originates from Smalltalk systems.

Another alternative is having a type table per polymorphic method, instead of having a polymorphic method table (VMT) per type. It requires whole program analysis, but makes efficient multiple inheritance possible. Some Eiffel compilers use such a method (more here, look for "How do I implement multiple inheritance efficiently?").

The last one also mentions another method, a switch statement based approach (inspect in Eiffel ~ switch in C). SmartEiffel uses a variant of it, it makes a binary search based on the class ID. It also requires whole program analysis, but can sometimes be more efficient than VMT on current systems thanks to better instruction cache behavior. (more here, look for "Efficient Dynamic Dispatch without Virtual Function Tables").

cyco130
  • 4,654
  • 25
  • 34
0

This might help you:

Virtual method table: Comparison with alternatives

Different compiler vendor may choose a different method... But the final implementation needs to be compliant with standard. which is this...

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf (section 10.3)

Constantin
  • 8,721
  • 13
  • 75
  • 126
vikrant
  • 393
  • 4
  • 15
0

I'll show you an example.

class B
{
private:
    int m_i;
public:
    void foo() { puts("B::foo"); }
    virtual void bar() { puts("B::bar"); }
};
class D : public B
{
private:
    int m_j;
public:
    virtual void bar() { puts("D::bar"); }
    virtual void asdf() { puts("D::asdf"); }
};

int main()
{
    D d;
    B *pb = &d;
    pb->bar();
}

Most compilers implements that code as follows:

struct B;
struct __vtbl_B_t
{
    void (*bar)(B * const this);
};
struct B
{
    const __vtbl_B_t *__vptr;
    int m_i;
};
void B__foo(B * const this) { puts("B::foo"); }
void B__bar(B * const this) { puts("B::bar"); }

const __vtbl_B_t __vtbl_B = { B__bar };
void B__ctor(B * const this)
{
    this->__vptr = &__vtbl_B;
}

struct D;
struct __vtbl_D_t
{
    __vtbl_B_t __base;
    void (*asdf)(D * const this);
};
struct D
{
    B __base;
    int m_j;
};
void D__bar(D * const this) { puts("D::bar"); }
void D__asdf(D * const this) { puts("D::asdf"); }

__vtbl_D_t __vtbl_D = { { (void (*)(B * const))D__bar }, D__asdf };
void D__ctor(D * const this)
{
    B__ctor((B * const)this);
    this->__base.__vptr = (const __vtbl_B_t *)&__vtbl_D;
}

int main()
{
    D d;
    D__ctor(&d);

    B *pb = (B *)&d;

    (*pb->__vptr->bar)(pb);
}

Output:

D::bar

Even if your language is not C++, the behaviors of compilers are similiar.

ikh
  • 10,119
  • 1
  • 31
  • 70