mathInit = (void* (*)())dlsym(handle, "CreateMathOperationInstance");
Here you are using dlsym()
to find this symbol in the shared library. This must be a function with C
linkage, since the symbol name is not mangled. This is important, and keep this in mind, while you're staring at this line:
cout<< mathInstance->AddInt(num1, num2)<<endl;
Here, AddInt
is a method of the class pointed to by mathInstance
. A class method is just another function, except that it always takes a hidden this
pointer as an extra argument. That's what a class method is, in so many words, and this actually turns out to be the case with a typical C++ implementation. C++ technically does not actually require this to be the case. A C++ implementation is free to implement methods in whatever manner produces the results that are compliant with the C++ specification. But, in practical terms, in a typical C++ implementation this is what a class method actually is. A function with an extra parameter that's referenced as this
.
Therefore, in a manner of speaking, the above line is basically equivalent to:
cout<< mathOperationClass::AddInt(mathInstance, num1, num2)<<endl;
This basically is what's going on here, speaking very loosely.
This mathOperationClass::AddInt
method/function is, presumably, in the same shared library that you dlopen
-ed; and because you dlopen
-ed it and you did not actually link to it, you have a reference to this symbol, and this reference cannot be resolved at runtime, hence your runtime undefined symbol error.
The only way you can even the slightest hope of invoking this class method -- if it can be invoked at all in this manner -- is by also using dlsym()
. But in order to have even the slightest prayer of actually being be able to pull this off, a whole bunch of things need to happen just right.
First, you have to figure out the actual mangled C++ symbol name. Using my Linux x86_64 g++ compiler as a reference, the mangled name for this method would be "_ZN18mathOperationClass6AddIntEii". With that in hand, you can use dlsym
to find this symbol (or whatever your C++ implementation's actual mangled symbol name for this method is) in your shared library.
And once you have this symbol, what now? Well, let's hope that your C++ implementation does, indeed, have a hackable C++ ABI where you can invoke a class method by explicitly passing it an extra this
parameter, something like this:
int (*addInt)(mathOperationClass *, int, int)=
reinterpret_cast<int (*)(mathOperationClass *, int, int)>
(dlsym(handle, "_ZN18mathOperationClass6AddIntEii"));
cout << (*addInt)(mathInstance, num1, num2) << endl;
This entire house of cards will collapse unless it can be confirmed that C++ methods can be invoked this hackish way, in your C++ implementation's ABI. Since you're already using dlopen
() you're already in non-portable territory, using your C++ implementation-specific resources, so you might as well and figure out whether your C++ methods can be called this way. If not, you'll have to figure out how they can be called, using a plain pointer.
And now for something completely different...
Having said all of the above:
There is one way you can likely avoid dealing with this mess: by making this class method a virtual class method. Virtual class methods are dispatched via an internal virtual function table. So, just try declaring this AddInt
method as a virtual class method, and calling it, as is. It's very likely to work in your C++ implementation, since the compiler will not emit, in this instance, an explicit symbol reference for mathOperationClass::AddInt
. It will find the method via the virtual function table that's quietly attached to every instance of the object.
Of course, you also need to keep in mind what virtual functions are, and the implications of them. But, in nearly all cases this is a pretty cheap way to call methods of classes that are dynamically loaded from a shared library.