cvbrgava
cvbrgava

Reputation: 1

Unexpected vTable look-up for non-virtual method in C++

The code snippet below explains the problem:

class base_obj_with_virtual_func
{
public:
    int variable_int;
    virtual void print_name() { std::cout << "Base obj " << this << std::endl; }
};

class derived_1 : public base_obj_with_virtual_func
{
public:
    int variable_int_1;
    void print_name() { std::cout << "Derived_1 obj " << this << std::endl; }
};

class derived_2 : public derived_1
{
public:
    int variable_int_2;
    void print_name() override { std::cout << "Derived_2 obj " << this << std::endl; }
};

void main()
{
    derived_2 derived_2_obj;

    base_obj_with_virtual_func* base_ptr = &derived_2_obj;
    base_ptr->print_name(); // compiler replaces with vtable[0] lookup
                            // In this case, vtable[0] points to derived_2::print_name()
                            // Expected behavior

    derived_1* derived_1_ptr = &derived_2_obj;
    derived_1_ptr->print_name(); // non-virtual function. Should not cause any vtable lookup
                                 // However, this invokes derived_2::print_name()
                                // Unexpected behavior
}

I was expecting output to be

Derived_2 obj XXX 
Derived_1 obj XXX

However, the output is:

Derived_2 obj XXX 
Derived_2 obj XXX

This output is only possible if the non-virtual method derived_1::print_name() is causing a vTable lookup. The lookup then invokes derived_2::print_name()

Below is the object layout generated by visual-studio.


// Object layout
class derived_2 size(32):
    +---
 0  | +--- (base class derived_1)
 0  | | +--- (base class base_obj_with_virtual_func)
 0  | | | {vfptr}
 8  | | | variable_int
    | | | <alignment member> (size=4)
    | | +---
16  | | variable_int_1
    | | <alignment member> (size=4)
    | +---
24  | variable_int_2
    | <alignment member> (size=4)
    +---

// VTable entries
derived_2::$vftable@:
    | &derived_2_meta
    |  0
 0  | &derived_2::print_name


The vTable has only one entry. I am assuming it is corresponding to the base_obj_with_virtual_func::print_name()

This means that the non-virtual method derived_1::print_name() doesn't have a vTable entry. But is still behaving like a virtual function!

Question = Why is non-virtual method derived_1::print_name getting redirected to derived_2::print_name ?

Upvotes: 0

Views: 28

Answers (0)

Related Questions