Imagine you have the following classes:
class A {
public:
virtual void print() { printf("A\n"); }
};
class B : public A {
public:
virtual void print() override { printf("B\n"); }
};
class C : public B {
// no override of print
};
And now if you create an instance of B and call print:
B * b = new B;
b->print();
Will this method be called virtually? In other words, will the exact method to be called determined at compile-time or run-time?
Theoretically it can be determined at compile-time, because we know, that none of sub-classes of B overrides that method, so no matter what I assign into pointer to B B * b = new C; b->print();
, it will always call B::print()
.
Does the compiler know it too and save me from unnecessary overhead of the virtual call?
When the method is declared as virtual in a base class, and the same definition exists in a derived class, there is no need for override, but a different definition will only work if the method is overridden in the derived class. Two important rules: By default, methods are non-virtual, and they cannot be overridden.
You can override any method of a class, the question is really how to access the non-virtual method, or should I have made the method virtual in the first place. With a virtual method, you always access the overridden method regardless of the class variable used to reference it.
New! Save questions or answers and organize your favorite content. Learn more.
Only the pure virtual methods have to be implemented in derived classes, but you still need a definition (and not just a declaration) of the other virtual methods. If you don't supply one, the linker might very well complain.
Theoretically it can be determined at compile-time, because we know, that none of sub-classes of B overrides that method
You cannot determine this at compile time in general case, because C++ compiler deals with one translation unit at a time. A class from a different translation unit, say, class D : public B
could override the method. However, the compiler may have no visibility into the translation unit of class D
at the time the call to b->print()
is translated, so the compiler must assume a virtual call.
In order to address this shortcoming C++11 introduced final
keyword, which lets programmers tell the compiler that there would be no further overrides down from this level of inheritance hierarchy. Now the compiler can optimize out the virtual call, and also enforce the requirement of no further overrides.
Regarding
” Theoretically it can be determined at compile-time, because we know, that none of sub-classes of B overrides that method, so no matter what i assign into pointer to B B * b = new C; b->print();, it will always call B::print().
Yes.
However, whether the compiler will do this optimization depends entirely on the compiler, what it knows, and what you tell it to do.
What the compiler knows depends on many factors, such as
Are there classes defined in multiple translation units that are compiled separately?
Are you using global optimization?
Are you perhaps using the keyword final
to inform the compiler?
With your specific example,
B * b = new B;
b->print();
where print
is virtual, I would feel pretty confident that it would be called non-virtually regardless of compiler, because here the compiler knows what b
refers to. Let's check.
OK, with MinGW g++ 5.1 and option -O2
(I didn't try anything else) the call is compiled down to a direct call of puts
, even bypassing the printf
.
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