Why are virtual functions handled at runtime?
Asked Answered
J

4

11

Surely the compiler is smart enough to deduce exactly what function you want for some cases, yet how come other cases require run-time support?

Julejulee answered 31/12, 2013 at 4:8 Comment(5)
Imagine this tree: B<-A->C. Where A has a pure virtual method, m, which is implemented in both B and C subtypes. Now, given an a of type A, how should the compiler dispatch: a.m()? (It will either be the method in B or C - but which one? Compiler doesn't know either.)Rousing
If you have a runtime generated container of objects which are a mixture of base and derived classes and you want to call their member functions, how would the compiler know which function to call?Wilsey
What is the concern? Virtual functions are almost free: they require allocation of a function pointer in the object. The cost of the extra indirection is a few dozen nanoseconds on a modern processor.Mickeymicki
@Mickeymicki Such generalizations don't always hold though, and it depends on the nature of your code. Virtual functions can be expensive for high performance simulations using long running tight loops for example (where the overhead of each function call adds up). There's also cache misses to worry about.Wilsey
@wallyk: No concern. In most cases, the overhead of virtual functions is minimal. I'm simply curious as to why things are the way they are. I wanted to know why they couldn't be handled at compile-time.Julejulee
P
11

Because we don't always know, what instance we will face at runtime.

For example, you have classes: SuperClass, Subclass1 and Subclass2, and they all have a method doACoolThing(). The user presses a button 0, 1 or 2, and, depending on his input, an instance of the appropriate class is created, and its doACoolThing() method is called.

There is no way for us (and the compiler too) to figure out what class's method will be called at runtime.

That's why such tricks require a runtime support.

A small example to illustrate an idea (P.S. don't write the code like this, it's here just to illustrate polymorphism :) ):

#include <iostream>

using namespace std;

class SuperClass
{
public:
    virtual void doACoolThing();
};

void SuperClass::doACoolThing()
{
    cout << "Hello from the SuperClass!" << endl;
}

class Subclass1 : public SuperClass
{
    virtual void doACoolThing() override;
};

void Subclass1::doACoolThing()
{
    cout << "Hello from the Subclass1" << endl;
}

class Subclass2 : public SuperClass
{
    virtual void doACoolThing() override;
};

void Subclass2::doACoolThing()
{
    cout << "Hello from the Subclass2" << endl;
}

int main()
{
    int userInput;
    cout << "Enter 0, 1 or 2: ";
    cin >> userInput;
    SuperClass *instance = nullptr;
    switch (userInput)
    {
        case 0: 
            instance = new SuperClass();
            break;
        case 1:
            instance = new Subclass1();
            break;
        case 2:
            instance = new Subclass2();
            break;
        default:
            cout << "Unknown input!";
    }

    if (instance)
    {
        instance->doACoolThing();
        delete instance;
    }
    return 0;
}
Pursuit answered 31/12, 2013 at 4:13 Comment(1)
It didn't occur to me to think that the dynamic type could be decided from an unpredictable source like user input instead of something "hardcoded". Because we can't predict the type, we HAVE to handle polymorphism at run-time. I appreciate the answer.Julejulee
C
6

Consider the following code:

Derived1 var1 = <something>;
Derived2 var2 = <something>;
int x;
cin >> x;
Base *baseptr = x ? &var1 : &var2;

baseptr->virtfun();

The compiler doesn't know what the user will input, so it can't tell whether baseptr points to an instance of Derived1 or Derived2.

Counterfactual answered 31/12, 2013 at 4:17 Comment(0)
P
2

Say you depend on a user input to decide which of the subclass you want create.

class Base
{
public:
   void f();
}
class Derived1: public Base
{
public:
   void f();
}
class Derived2: public Base
{
public:
   void f();
}

int choice;
cin >> choice;

Base *pB = NULL;
if (choice == 1)
{
   pB = new Derived1;
}
else
{
   pB = new Derived2;
}
pB->f();

Without virtual function, how can the compiler know the correct version of f to call at runtime if you want to select f depending on different instances? Just no way.

Personalty answered 31/12, 2013 at 4:20 Comment(0)
S
1

Reasons include:

  • there's some input (keyboard, mouse, file, database, network, hardware device etc.) only known at runtime which will determine the actual data type and consequently the member functions that need to be invoked

  • functions that aren't inlined and are called from many places with disparate derived objects will need to dispatch virtually - the alternative for static dispatch amounts to "instantiations" per type (ala templates, and with some code bloat potential implied)

  • functions that use virtual dispatch can be compiled in objects that are linked into executables and called with pointers to argument types they never knew about at the time they were compiled

  • virtual dispatch can provide a kind of "compilation firewall" (much like the pointer-to-Implementation or pImpl idiom), such that changes to the files defining the function implementation don't require changes to the headers containing the interfaces, which means client code needs to be relinked but not recompiled: that can save enormous amounts of time in an enterprise environment

  • it's often just too complicated to keep track of the type at various points during the program: even if it is possible to know from compile-time analysis of the code, the compiler's only obliged to make limited efforts to recognise compile-time constant/deterministic data, and that doesn't involve tracking arbitrarily complex operations on say constainers of pointers-to-base that might be use when a call is eventually virtually dispatched.

    • this is especially true of containers, and variables implementing state machines with complex rules about when the pointer-to-base should be deleted and a reset to a different derived type
Schleswigholstein answered 31/12, 2013 at 5:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.