This question follows up on stackoverflow.com/q/2391679
One of the classic examples of virtual
functions is
class Shape
{
public:
virtual string draw() = 0;
};
class Circle : public Shape
{
public:
string draw() { return "Round"; }
};
class Rectangle : public Shape
{
public:
string draw() { return "Flat"; }
};
void print (Shape& obj)
{
cout << obj.draw();
}
However, we can instead pass an auto
parameter in C++ 14
class Circle
{
public:
string draw() { return "Round"; }
};
class Rectangle
{
public:
string draw() { return "Flat"; }
};
void print (auto& shape)
{
cout << shape.draw();
}
When should we prefer virtual
functions or auto
parameters?
Is the latter more efficient due to early binding?
C++ has two different mechanisms in place to write a piece of code that behaves differently based on the types of the objects acted on:
virtual
functions and inheritance, which work at runtime, andYour example with auto
parameters (which apparently weren't actually adopted in C++14 except for lambda functions) works with templates. The code you've written is equivalent to
template <typename T>
void print(T& shape) {
cout << shape.name();
}
This code assumes that the type of T
can be determined at compile-time, since the compiler needs to know the type of T
in order to fill in the template. Once the compiler knows this it can say "Ah, I know what that type is! I'll generate code to directly call the name
function in that type, and I know exactly what function that will call."
On the other hand, virtual functions and inheritance work at runtime. For example, suppose you want to write a function that reads some data from the network, then hands back either a Circle
or a Rectangle
. You might have some code like this:
Shape* myShape = decodeNetworkData();
Here, all the compiler knows is that myShape
points to some sort of Shape
, but it can't tell whether that's a circle or a square. Therefore, if you were to call
cout << myShape->name();
then the compiler would say "I know you're calling some version of name
, but I don't know which one. But that's okay! I'll generate some code that looks at the dynamic type of myShape
(the type of the thing it actually points at) and uses that to look up which function to call."
Notice that the code the compiler will generate in each case is different and the behavior will be different. In the first case, the compiler knows exactly which function to call. In the second, the compiler doesn't know what function to call, and has to generate some extra code to make things work. But, on the other hand, if you didn't have a Shape
type with a virtual name
function, you could make the "decode the bytes of the network" code snippet work with your first function, since the compiler would have to know, in advance, what type it was going to see come in over the network.
There was a proposal to mark this question as a duplicate of this older question on templates and inheritance, even though it's not superficially the same question. Once you know that the auto
keyword in this context means "this is really a template function," you can look over that other proposed question to get some additional examples of the difference between static polymorphism (with templates) and runtime polymorphism (with virtual functions).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With