2

Base having a virtual function and Derived also having one virtual function like this,

class Base
{
    private:
        int i;
    public:
        Base(int data = 9):i(data)
        {
            cout << "In Base class constructor" << endl;
        }
        void display()
        {
            cout << "In Base class" << endl;
            cout << "i = " << i << endl;
        }
        virtual ~Base()
        {
            cout << "In Base class destructor" << endl;
        }
};

class Derived: public Base
{
    private:
        int j;
    public:
        Derived(int data = 10):Base(11),j(data)
        {
            cout << "In Derived class constructor" << endl;
        }
        virtual void display()
        {
            cout << "In Derived class" << endl;
            cout << "j = " << j << endl;
        }
        ~Derived()
        {
            cout << "In Derived class destructor" << endl;
        }
};

Now in gdb I see the total size of the Derived class object is 16 bytes (int+int+_vptr+_vptr), but when I print each object in gdb I'm getting confused, for base class it's showing like this

$1 = {_vptr.Base = 0x401010, i = 11} and it's fine, but for derived it's showing something like this

$2 = {<Base> = {_vptr.Base = 0x401010, i = 11}, j = 10}

I'm not seeing the virtual pointer of the derived class. As per my understanding in addition to the base class virtual pointer which is inherited, there should be one more virtual pointer in the derived class that should point to it's own virtual table. Am I doing something wrong here or is there any other way to get it?

10
  • 2
    What's the type = thing? Commented Jan 8, 2014 at 1:46
  • I just printed from gdb using ptype. Not actual code Commented Jan 8, 2014 at 1:48
  • Also why is the destructor taking an int? Commented Jan 8, 2014 at 1:50
  • 2
    Show verbatim code, not whatever this is. Commented Jan 8, 2014 at 1:50
  • 2
    @Sarath, well, gdb looks drunk, as far as I can tell. Commented Jan 8, 2014 at 1:54

3 Answers 3

4

The derived class has its own vtable. So objects of that type have a single pointer to it. That vtable contains entries that point to Bases member functions if they aren't overridden. So there is no need for a pointer to Bases vtable in objects of type Derived.

The reason _vptr.Base appears in Derived is because you didn't override any functions. The compiler doesn't generate a vtable for Drived because it will just be a duplicate of Bases.

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

6 Comments

You are saying if I'm not overriding those then derived class _vptr also points to the base vtable?
@Sarath, no. The vtable of Derived will contain entries that point to the same function as the entries in Bases vtable. But the vtables are seperate.
Sorry if I'm making this worse, is there anyway I can see that pointer in gdb, currently I'm not able to view it when I print the object.
@Sarath, Like Dietmar said, the actual structure of the vtable and it's function will depend on the ABI. You'd need that to reinterpret the pointer and make sense of it. Rather than learning about this from examining code in the debugger, I recommend you look for a resource that explains how dynamic dispatch is implemented in c++ on a somewhat abstract level.
@Sarath, I reread your quesiton and understand your confusion. Please see my edit.
|
1

With single inheritance, there is typically just one virtual function pointer: it points to something like an array of function pointers. The number of entries contributed by the base class is known and the derived class just tags its own virtual functions to the end.

Of course, how the virtual function table actually works exactly depends on the respective ABI. You can have have a look, e.g., at the Itanium C++ ABI which is used on Linuxes and possibly on other systems.

1 Comment

Thanks for the ABI link: the one I used to use stopped working a while ago.
1

The derived class doesn't have a separate, additional pointer to its vtable - rather, the vtable pointer inherited from the base class will be overwritten to point to the derived class's vtable as the derived class's constructor runs (and later reverted as the destructor runs).

That way, when operations are done on a Base* or Base& to the Base member embedded in a constructed derived object, the pointer to the VDT seen (at the usual offset into the Base object) allows dispatched to the derived class's methods.

Comments

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.