Say I have the following code:
template <class Derived>
class Base {
public:
virtual void foo_impl() = 0;
void foo() {
static_cast<Derived*>(this)->foo_impl(); //A
(*static_cast<Derived*>(this)).foo_impl(); //B
}
};
class Derived : public Base<Derived> {
private:
void foo_impl() {
bar();
}
};
A few questions:
Will line A generate a virtual function call? Although the majority of what I can find on the internet recommends doing things this way, to me I don’t see how the compiler can do static dispatch considering that a pointer to Derived could still actually point to an object of type Derived2 where Derived2 : public Derived.
Does line B fix the issue I brought up in my previous point (if applicable)? It seems like it would, considering that now the call is not on a pointer any more and thus using *. would avoid a virtual function call. But if the compiler treats the dereferenced cast as a reference type, it could still generate a virtual function call… in that case, what is the workaround?
Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?
Yes.
foo_impl()is virtual andDerivedoverrides it. Even thoughfoo_impl()inDerivedis not explicitly tagged asvirtual, it is in the base class, and this is enough to make it a virtual function.No. It does not matter if the call is on a pointer or on a reference: the compiler still won’t know whether you are invoking the function
foo_impl()on an instance of a class that derives fromDerived, or on a direct instance ofDerived. Thus, the call is performed through a vtable.To see what I mean:
Finally:
In theory, yes. The
finalkeyword would make it impossible to override that function in subclasses ofDerived. Thus, when performing a function call tofoo_impl()through a pointer toDerived, the compiler could resolve the call statically. However, to the best of my knowledge, compilers are not required to do so by the C++ Standard.CONCLUSION:
In any case, I believe what you actually want to do is not to declare the
foo_impl()function at all in the base class. This is normally the case when you use the CRTP. Additionally, you will have to declare classBase<Derived>afriendofDerivedif you want it to accessDerived‘sprivatefunctionfoo_impl(). Otherwise, you can makefoo_impl()public.