1

Consider the following sample code:

class Base {
public:
    void f();
    virtual void vf();
};

class Derived : public Base {
public:
    void f();
    void vf();
};

#include <iostream>
using namespace std;

void Base::f() {
    cout << "Base f()" << endl;
}

void Base::vf() {
    cout << "Base vf()" << endl;
}

void Derived::f() {
    cout << "Derived f()" << endl;
}

void Derived::vf() {
    cout << "Derived vf()" << endl;
}

int main()
{
    Base b1;
    Derived d1;
    b1.f();
    b1.vf();
    d1.f();
    d1.vf();

    Derived d2;     // Derived object
    Base* bp = &d2; // Base pointer to Derived object
    bp->f();    // Base f()
    bp->vf();   // which vf()?

    return 0;
}

The output of the run is:

Base f()

Base vf()

Derived f()

Derived vf()

Base f()

Derived vf()

Questions:

  1. In the line Base* bp = &d2, the object type is known at compile time. Then the decision of which function to use in the case of bp->vf(); can also be made at compile time right?

  2. Since the object type is known at compile time itself, is the power of virtual functions used in this sample program?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
nitin_cherian
  • 6,405
  • 21
  • 76
  • 127
  • Up to the compiler. Seems little point in rationalising about it. – Lightness Races in Orbit Dec 14 '11 at 16:01
  • @TomalakGeret'kal : So in this example the power of virtual functions is not used right? – nitin_cherian Dec 14 '11 at 16:04
  • 1
    This question doesn't really make sense. The language prescribes precisely which *behaviour* you get, and that's precisely what you see. What is unclear about that? A better thing to ask about would be the "cost of the dynamic dispatch". – Kerrek SB Dec 14 '11 at 16:07
  • @KerrekSB: My question is whether the program really exploits the power of virtual functions which is dynamic binding? – nitin_cherian Dec 14 '11 at 16:10
  • I think what @LinuxPenseur is asking in part 2 is: Will a virtual function pointer table be constructed for this example? – Lee Netherton Dec 14 '11 at 16:11
  • @ltn100 : Ya it can be put in that way also. – nitin_cherian Dec 14 '11 at 16:13
  • 2
    The only thing that matters is the "perceived" action at run time. The standard dictates how virtual functions should be executed so you can expect to see specific behavior at run time. In that sense, the power of virtual functions is preserved as you see the expected result. The compiler on the other hand is free to make optimizations when it can as long as the end result is the same. – Dave Rager Dec 14 '11 at 16:15
  • 1
    LinuxPenseur: the program is required to act as if it had, though underneath it can take shortcuts, as long as you can't tell the difference. So simple answer: yes it uses the vtable. – Mooing Duck Dec 14 '11 at 16:15
  • Your question is the wrong way round. Given how the program is *expected* to behave, you can conceive of the most general implementation that would always work. *Then* you can ask whether your particular program requires the most general implementation for the dynamic dispatch, or whether the compiler will be able to take advantage of static information to optimize... – Kerrek SB Dec 14 '11 at 17:22

4 Answers4

4

In the line Base* bp = &d2, the object type is known at compile time. Then the decision of which function to use in the case of bp->vf(); can also be made at compile time right?

Yes.
This is a part of compiler optimization which most modern day smart compilers will be able to do.

If an compiler can determine which function to call at compile time itself then it will do so. While this entirely depends on the compiler whether it can detect the exact function to call at compile time or run time, virtualism guarantees you the behavior you want for your program.

Since the object type is known at compile time itself, is the power of virtual functions used in this sample program?

Depends entirely on the compiler. Most modern day compilers will be able to evaluate this function call at compile time.

Alok Save
  • 202,538
  • 53
  • 430
  • 533
3

This program is trivial, and does indeed not demonstrate the power of virtual functions (or, more generally polymorphism) very well. Consider this change:

// add second derived class
class Derived2 : public Base {
public:
    void vf() { std::cout << "Derived2 vf()" << std::endl; }
};

// in main
int user_choice;
std::cin >> user_choice;
Base * ptr;
if (user_choice == 0)
    ptr = new Derived();
else
    ptr = new Derived2();
ptr->vf();

Here, the choice of the class depends on user-input - the compiler has no way to predict what type of object ptr will actually point to when the call ptr->vf(); is reached.

Björn Pollex
  • 75,346
  • 28
  • 201
  • 283
1

Well... YES and NO to both questions: it depends on what abstraction level you are arguing.

  • By a language standpoint, 1) is a misconception. The type for d2 is known, but when it comes d2 address to be assigned to bp, a conversion from Derived* into Base* will happen. From tham on, the static type of bp is Base* (because that is its declaration) and the dynamic type it points to its Derived (because that's is what the run-time type information associate to the object refers to). From them on, every operation through bp assume Base* as a type, and requires a redirection for every virtual function.

  • By a compiler stand point, certain optimization can be done, and since in all your function your pb always points to a Derived, the virtual redirection can -in fact- be skipped. But that's due to the way your particular example is structured, not because of a language feature.

Emilio Garavaglia
  • 20,229
  • 2
  • 46
  • 63
1

In the line Base* bp = &d2, the object type is known at compile time. Then the decision of which function to use in the case of bp->vf(); can also be made at compile time right?

No, the decision to which function to use is done dynamically at run-time based on the type of the object, not the type of pointer/reference to that object. This is called dynamic binding. Compiler keeps a hidden pointer called virtual pointer or vptr which points to a table called virutal table. There would be one virtual table per class with atleast one virtual function (irrespective of how many objects created for the class). The virtual table contains address of the virtual functions of the class.

Since the object type is known at compile time itself, is the power of virtual functions used in this sample program?

Infact the object pointed to might not be known at compile time. Take an example of a method which takes the base class pointer as the parameter as shown below:

void draw(Shape *bp)
{
    bp->draw();
}

In this case, the actual object might be any shape derived from Shape. But the shape drawn depends on the actual type of the object passed in.

Sanish
  • 1,699
  • 1
  • 12
  • 21
  • I am afraid your answer to the first question contradicts with Als's answer to the same question. I think Als's answer is given after some research on compile optimization. But your explanation with the sample code can be coupled with Bjorn's example to get a nice understanding of power of virtual functions. Could you please verify whether your first answer is entirely correct? – nitin_cherian Dec 14 '11 at 16:35
  • I meant from a programmers perspective. The compiler might optimize the call, but it might depend on the abstraction level. – Sanish Dec 14 '11 at 17:36