I've encountered a strange case when the final
keyword is added to a virtual function declaration, with its definition on a separate .cpp file.
Consider the following example:
IClass.hpp
class IClass //COM-like base interface
{
protected:
virtual ~IClass(){} //derived classes override this
public:
virtual void release() final;
};
dllmain.cpp (shared library)
#include "IClass.hpp"
...
void IClass::release()
{
delete this;
}
...
main.cpp (standalone executable)
//various includes here
...
int main(int argc, char** argv)
{
/* From "IGameEngine.hpp"
class IGameEngine : public IClass
{
...
};
*/
IGameEngine* engine = factoryGameEngine();
...
engine->release();
return 0;
}
As it is, GCC 4.9.2 will report an undefined reference to 'IClass::release()'
My goal is to have IClass::release()
as non-overridable while having its implementation hidden inside the game engine's shared library.
Any suggestions?
final specifier (since C++11) Specifies that a virtual function cannot be overridden in a derived class or that a class cannot be derived from.
Properties of virtual function Virtual functions are resolved during run time resolved during run time hence it is a dynamic binding. Virtual functions are member functions of a class. Virtual functions are declared with the keyword virtual. Virtual function takes a different functionality in the derived class.
Rules for Virtual Functions Virtual functions cannot be static. A virtual function can be a friend function of another class. Virtual functions should be accessed using pointer or reference of base class type to achieve runtime polymorphism.
A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.
Did some digging regarding GCC's usage of final
and it turns out virtual functions marked final get "devirtualized", an optimization step that aims at speeding up virtual calls by using static dispatch, and possibly inlining them.
That explains the linker error, as it tries to link IClass::release()
into the executable but fails at finding it locally.
This "devirtualization" behaviour also appears on clang, but unlikely to happen with MSVC++
Partially related suggestion
In case you need a way to release an object through a pointer to its abstract class (or abstract base class):
The abstract base class needs a pure-virtual destructor Provide the destructor's default definition outside the class (empty scope) Implement the destructor on all derived classes, as usual
And if you're also dealing with shared libraries:Export a pair of Malloc/Free functions from the library Override the non-array new/delete operators and their respective std::nothrow
versions on your library's header fileCall the above Malloc/Free from the overriden operators
Since the interface implementation(s) will reside inside the library, export a factory function for each interface you deem client-constructible.
Just make sure exceptions aren't propagated through the gap between client and library.
This way, the client application can usedelete
on an object allocated by the library's CRT, free of hassle.
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