Understanding runtime polymorphism

closed account (o3hC5Di1)
Hi Everyone,

This may be a very dumb question, but I can't seem to figure it out and google is not much help (or I'm just using the wrong keywords). Please consider this small example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <string>

class base
{
    public:
        virtual void execute()=0;
};

class derived : public base
{
    public:
        void execute()
        {
            s.append(" with added stuff.");
            print();
        }
        void print()
        {
            std::cout << s;
        }
    private:
        std::string s="executing derived";
};

int main()
{
    base* b = new derived();
    b->execute();
}
executing derived with added stuff.



I understand why a pointer to base can call the overloaded execute() function. What I don't understand is that, with b being a pointer to base, how does the overloaded execute() function access members (s and print()) that are only defined in the derived class?

I envisioned the workings of base pointers as only being able to access the size of a base-object in memory, but that doesn't seem to be the full story?

Thanks very much in advance for your help, it's greatly appreciated as always.

All the best,
NwN
Last edited on
the answer to your question is 'virtual function table'. See

http://en.wikipedia.org/wiki/Virtual_method_table

Each constructor writes its own virtual functions in this table. It overwrites the already existing function pointer with the same signature.

In the constructor a virtual function shouldn't be called because it doesn't call the function of the inherited class because that constructor is called later.
Last edited on
closed account (o3hC5Di1)
Hi coder777,

Edit: I see where I went wrong in my understanding of vtables, the wikipedia article made it clear this time, in particular this section: http://en.wikipedia.org/wiki/Virtual_method_table#Invocation I guess I didn't understand enough C++ when I read it the first time.

I forgot that the this pointer is implicitly always passed to member functions, as the this pointer will be of derived type, it is able to access derived-class specific members.

Thanks very much again!

All the best,
NwN
Last edited on
So then you don't understand that completely.

A virtual function is indirectly called via the virtual function table for the provided signature (in your case the execute() function). Since all constructors previously placed their virtual function pointer in the virtual table the last derived class wins, i.e. that function will be called. In your case execute() from derived

Check it out: derive another time (from derived) and implement execute() again
closed account (o3hC5Di1)
Hi there,

Thanks for following up - I think I understand the vtable lookup, but my question was: how can a pointer to a base object execute a function which changes member data only defined in a derived class. In other words, how can a pointer to base, call execute() which changes s, which is not defined in base.

What I took away from the Wikipedia article you linked to was that the this pointer is passed to the function (as it is implicitly to any member function), allowing access to derived's private members. Then again, I'm not really sure how that would work - now I'm confused again. Here's how in my mind the call of b->execute() is done:

- base has defined execute() as a virtual function, so vtable loopup occurs
- execute is overridden in derived, so the vtable will contain a pointer to derived::execute
- the code at the address of that pointer is executed, after passing the this parameter to it
- the called code alters s and calls print()
- function returns

It's this penultimate step I don't understand, because doesn't the base pointer only point to the segment of a derived object they have in common? If so, how can a base pointer call a function that would alter values outside of that segment? I would guess the this-ptr, but that would mean the this-ptr is always of type derived?

All the best,
NwN
> how can a pointer to a base object execute a function which changes
> member data only defined in a derived class. In other words,
> how can a pointer to base, call execute() which changes s, which is not defined in base.

It is the responsibility of the implementation to ensure that when a non-static member function of derived is called (polymorphically via a pointer or reference to base), the this pointer is adjusted correctly. The function must be called with the type of the this pointer being 'pointer to derived'. That is, this must point to a valid object of type derived.

The standard does not have anything to say about how this is to be done; implementations use a variety of techniques to produce conforming behaviour. Lippman's (somewhat dated) 'Inside the C++ Object Model' describes the internals of a few implementations.
http://www.amazon.com/Inside-Object-Model-Stanley-Lippman/dp/0201834545

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>

struct base
{
    virtual ~base() {}

    void foo() const
    {
        std::cout << "base::foo -       const base* this points to " << this << '\n' ;
        this->bar() ;
    }

    virtual void bar() const = 0 ;
};

struct filler { virtual ~filler() {} char fill[1234] ; } ;

struct derived : filler, base
{
   virtual void bar() const override
   { std::cout << "derived::bar - const derived* this points to " << this << '\n' ; }
};

int main()
{
    derived d ;
    base& b = d ;
    b.foo() ;
}

http://coliru.stacked-crooked.com/a/ee59ce7e00a6a603
It's this penultimate step I don't understand, because doesn't the base pointer only point to the segment of a derived object they have in common?
No, it points to memory that contains at least the data/vtable associated with base.

In this case (because of new derived(); on line 28) it points to data of base plus the data of derived.

it's so that when a derived class adds data then the amount of memory allocated with new increases.

So yes, b points to base data and subsequent the derived data. Why not. base knows where it's data is and derived as well. Just the position of the vtable [pointer] must be fixed no matter what

closed account (o3hC5Di1)
Thank you very much for the explanation and book-tip Mr. Borges, very informative as always. I'm glad I was on the right track with the this pointer.

All the best,
NwN
The this pointer is what new returns
Topic archived. No new replies allowed.