Virtual Methods¶
Simple Is-A Relationship Is Not Enough¶
#include <iostream>
class Base
{
public:
void method() const
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived : public Base
{
public:
void method() const
{
std::cout << "Derived::method()" << std::endl;
}
};
int main()
{
Derived d;
Base* b = &d; // <--- **is-a**: Derived is converted to Base, **without** a cast
b->method(); // <--- **Question**: Base::method() or Derived::method()?
return 0;
}
$ ./inher-oo-derived-novirtual-base-usage
Base::method()
Questions
If
Base* b
actually points to aDerived
object, why isn’tDerived::method()
called?If
Derived
is-aBase
, how do I use it as-aBase
?In other words: how to I use a
Base*
to callDerived::method()
Usage Scenario
Consider a system that uses thermometers to measure temperature
There are a million of different thermometers out there that can answer me that question: what’s the temperature?
In software, I don’t want to care
I only want to know the temperature
I don’t want to expose the physics of thermometers to my system
Enter virtual
¶
Answer
Use
virtual
on those methods that need dynamic dispatch⟶ through the
Base*
, the actual dynamic type is determined
#include <iostream>
class Base
{
public:
virtual void method() const
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived : public Base
{
public:
virtual void method() const
{
std::cout << "Derived::method()" << std::endl;
}
};
int main()
{
Derived d;
Base* b = &d;
b->method(); // <--- **dynamic dispatch**: calling Derived::method()!
return 0;
}
$ ./inher-oo-derived-virtual-base-usage
Derived::method()
Question
Why isn’t that the default?
Answer
Performance ⟶ indirect function call cannot be default
Caution: virtual
¶
C++ lets you complete freedom
virtual
is just a mechanism to achieve dynamic dispatch⟶ no policy!
If you want to use
Base*
polymorphically, this is the place wherevirtual
is written
Wrong
virtual
has to come at dynamic dispatch entry point!
#include <iostream>
class Base
{
public:
void method() const // <--- ERROR: virtual omitted -> **no dynamic dispatch**
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived : public Base
{
public:
virtual void method() const
{
std::cout << "Derived::method()" << std::endl;
}
};
int main()
{
Derived d;
Base* b = &d;
b->method(); // <-- WRONG: calling Base::method()!
return 0;
}
$ ./inher-oo-derived-virtual-base-usage-wrong
Base::method()
Obscure but correct
virtual
at dynamic dispatch entry point is sufficient⟶ propagates down the line
Not quite readable though
#include <iostream>
class Base
{
public:
virtual void method() const
{
std::cout << "Base::method()" << std::endl;
}
};
class Derived : public Base
{
public:
void method() const // <--- virtual omitted: correct but less readable
{
std::cout << "Derived::method()" << std::endl;
}
};
int main()
{
Derived d;
Base* b = &d;
b->method(); // <-- correct: calling Derived::method()
return 0;
}
$ ./inher-oo-derived-virtual-base-usage-obscure
Derived::method()