Here is my problem. I have a base class and a derived class which overrides some methods from the base class. For simplicity consider the following example:
struct base
{
virtual void fn()
{/*base definition here*/}
};
struct derived : base
{
void fn()
{/*derived definition here*/}
};
In my actual program, these classes are passed as arguments to other classes and are called in other methods, but for the sake of simplicity let's create a simple function that takes as argument either the base or derived class. I can simply write
void call_fn(base& obj)
{obj.fn();}
and the call to the appropriate function will be resolved at run-time due to the virtual functions.
I am worried, however, that if the call_fn
, is to be called million times (which in my case it will as my actual application is a simulation experiment), I will get a significant overhead which I would like to avoid.
So, I was wondering if using a static_cast could actually tackle the problem. Maybe something like this:
template <typename T>
void call_fn(base& obj)
{(static_cast<T*>(&obj))->fn();}
In this case, the function call would be done as call_fn<base>(obj)
for calling the base method or call_fn<derived>(obj)
for calling the derived method.
Will this solution avoid the vtable overhead or will it still be affected? Thanks in advance for any replies!
By the way, I am aware of the CRTP but not very familiar with it. That is why I would like to know the answer to this simple question first :)
All classes with a virtual method will have a single vtable that is shared by all objects of the class. Each object instance will have a pointer to that vtable (that's how the vtable is found), typically called a vptr. The compiler implicitly generates code to initialize the vptr in the constructor.
For every class that contains virtual functions, the compiler constructs a virtual table, a.k.a vtable. The vtable contains an entry for each virtual function accessible by the class and stores a pointer to its definition. Only the most specific function definition callable by the class is stored in the vtable.
The compiler places the addresses of the virtual functions for that particular class in the VTABLE. In each class with virtual functions, it secretly places a pointer, called the vpointer (abbreviated as VPTR), which points to the VTABLE for that object.
You can imagine what happens when you perform inheritance and override some of the virtual functions. The compiler creates a new VTABLE for your new class, and it inserts your new function addresses using the base-class function addresses for any virtual functions you don't override.
Will this solution avoid the vtable overhead or will it still be affected?
It will still use dynamic dispatch (whether that causes any noticeable overhead is a completely different question). You can disable dynamic dispatch by qualifying the function call as in:
static_cast<T&>(obj).T::fn();
Although I would not even try to do so. Leave dynamic dispatch, then test the performance of the application, do some profiling, do further profiling. Profile again to make sure that you understand what the profiler is telling you. Only then, consider making a single change and profile again to verify whether your assumptions are correct or not.
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