C ++: virtual function calls with a pointer to a derived class still have vlookup

It’s just interesting, if I have a pointer to the most derived class and call on it a virtual function that defines the most derived class, still causes a search in the virtual table?

In the end, during compilation, the compiler knows that this class is the most derived, it knows that it defines a virtual function, there is no ambiguity, so you just need to consider it as a non-virtual function?

Or am I missing something?

The reason I ask is because I am writing a template that I want to extract later to merge the code, and functions that differ will be implemented in derived classes.

There is no need to define these functions as virtual in the template, but if this virtual call is ignored later, I plan to do it anyway, just to visualize for the artist later which functions should be written.

+7
c ++ inheritance virtual templates
source share
1 answer

Disclaimer: Compiler Optimization

This answer is about compiler optimization methods. Your compiler may or may not support them. Even if it supports the technique you are trying to use, they may not be available at your chosen optimization level.

Your mileage may vary.

Most derived class

A compiler can truly devirtualize a call if it knows that it is indeed the most derived class. How this can be achieved is discussed here . Example:

struct Base { virtual void call_me_virtual() = nullptr; }; struct Derived final : Base { void call_me_virtual() override { } }; void dosomething(Derived* d) { d->call_me_virtual(); } 

Interestingly, if this is not done, you can always get someone else from your class in a different translation unit, so the compiler will not know about this "more derived" class in your current translation unit.

Another way to ensure that a class must be the most derived is to put it in an anonymous namespace:

 struct Base { virtual void call_me_virtual() = nullptr; }; namespace { struct Derived : Base { void call_me_virtual() override { } }; void dosomething(Derived* d) { d->call_me_virtual(); } } 

This works because Derived not known outside the current translation unit, which implies that any more derived class must be inside the current translation unit. However, this means that dosomething cannot be (correctly) called from outside the current compilation unit, so I also gave it an internal connection.

One of the exceptions to this rule are compilers, which can prove that an object arises from its representation, for example. if Derived is the most derived type in your current translation unit, and the object must always come from the current translation unit, then it cannot be from any derived type. The scope of this analysis can be expanded by optimizing the entire program.

Known type

A more common case is the fact that the compiler knows which type of object, for example, in both cases:

 Derived d; d.call_me_virtual(); Base* b = new Derived; b->call_me_virtual(); 

The compiler can deduce that d.call_me_virtual and b->call_me_virtual will always resolve to Derived::call_me_virtual and thus Derived::call_me_virtual (and even embed) the call in this instance.

In the first case, this requires knowledge that an object of type Derived , in contrast to an object of a very similar type, Derived& , can only be a Derived object, and not something derived from it.

The second case requires static type analysis, which is performed by modern optimizing compilers. Seeing that b always initialized with a pointer to a Derived object, the compiler can prove which function will be called by b->call_me_virtual .

Completed Item Function

A similar case occurs when you complete one member function:

 struct Base { virtual void call_me_virtual() = nullptr; }; struct Derived : Base { void call_me_virtual() override final { } }; void dosomething(Derived* d) { d->call_me_virtual(); } 

While d can point to something derived from Derived , the call_me_virtual method call_me_virtual no longer be changed, so the compiler knows that Derived::call_me_virtual will always be called, and therefore can virtualize this call.

+5
source share

All Articles