I am having main program which has one base class that needs to be used by shared library.
Base class has some pure virtual method that derived class in shared library needs to be over written.
Main program load shared library using dlopen system call.
dlopen("shared file name", RTLD_NOW|RTLD_GLOBAL);
Base class
class RateComputer
{
public:
RateComputer();
virtual ~RateComputer();
virtual void OnMarketData() = default;
private:
};
Derived class in shared library.
class WeightedRateComputer : public RateComputer
{
public:
WeightedRateComputer();
~WeightedRateComputer();
void OnMarketData() override;
private:
};
and implement
WeightedRateComputer::WeightedRateComputer()
{
printf("in Construct\n");
}
void WeightedRateComputer::OnMarketData()
{
printf("in OnMarketData\n");
}
extern "C" WeightedRateComputer* createObj()
{
return new WeightedRateComputer();
}
While compilation of binary and so file I have added -rdynamic flag. But during loading of library with dlopen it gives error "undefined symbol: _ZTI12RateComputer".
int main()
{
void *handle = dlopen("../xx.so", RTLD_LAZY |RTLD_GLOBAL);
if (handle == NULL)
{
printf("%s\n", dlerror()); //throw error here
return 0;
}
return 0;
}
As Constructor and Destructor are declared in your RateComputer class, they need to be defined.
At least, you can use default c++11 keyword to use default implementation.
Moreover, as your RateComputer class is an interface, your OnMarketData method should be pure virtual, hence only declared in the interface and implemented in derived classes.
Here's the RateComputer class code I end up with :
class RateComputer
{
public:
RateComputer() = default;
virtual ~RateComputer() = default;
virtual void OnMarketData() = 0;
};
Hope this helps.
Related
I want to load libraries at run time. I have a base class "Base" and two derived classes "Derived1" and "Derived2" which should be loaded at runtime. I am using the approach from this answer with some small modifications. The code compiles perfectly when I define only one derived class, but it fails to compile when several derived classes are defined. The compilation error is the following:
multiple definitions of 'create'
I think that the problem is "C" doesn't allow overloading of function names. How would one solve this problem?
The important point is that since I don't know how many .so files exist, I want to have one handler for all .so files. The details of the code are given below:
base.hpp:
class Base {
public:
virtual ~Base() {}
virtual void foo() const = 0;
};
using Base_creator_t = Base *(*)();
derived1.hpp:
#include "Interface.hpp"
class Derived1: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived1;
}
}
derived2.hpp:
#include "Interface.hpp"
class Derived2: public Base {
public:
void foo() const override {}
};
extern "C" {
Base * create() {
return new Derived2;
}
}
Dynamic shared library handler: Derived_factory.hpp:
#include <dlfcn.h>
class Derived_factory {
public:
Derived_factory(char* path) {
handler = dlopen(path, RTLD_NOW);
if (! handler) {
throw std::runtime_error(dlerror());
}
Reset_dlerror();
creator = reinterpret_cast<Base_creator_t>(dlsym(handler, "create"));
Check_dlerror();
}
std::unique_ptr<Base> create() const {
return std::unique_ptr<Base>(creator());
}
~Derived_factory() {
if (handler) {
dlclose(handler);
}
}
private:
void * handler = nullptr;
Base_creator_t creator = nullptr;
static void Reset_dlerror() {
dlerror();
}
static void Check_dlerror() {
const char * dlsym_error = dlerror();
if (dlsym_error) {
throw std::runtime_error(dlsym_error);
}
}
};
main.cpp:
#include "Derived_factory.hpp"
int main(){
Derived_factory factoryOne("Derived1.so");
std::unique_ptr<Base> baseOne = factoryOne.create();
baseOne->foo();
Derived_factory factoryTwo("Derived2.so");
std::unique_ptr<Base> baseTwo = factoryTwo.create();
baseTwo->foo();
return 0;
}
The problem is not extern "C". The problem is you have multiple definitions of the same function.
Base * create() is indistinguishable from Base * create()
What you're trying to do is to have the same function in two different loadable modules. But what you're doing instead is putting both implementations (with the same name and signature!) of this function into the main module, which of course results in multiple definition error.
What you should do instead is put the create functions into the *.cpp files, i.e. derived1.cpp and derived2.cpp, omit their definitions from the *.hpp files, and compile the shared objects from these *.cpp files. I've modified your project to achieve this, see the live demo.
I am encountering a very strange issue in my code... I've spent now a whole afternoon and cannot get nor heads nor tails on it. But maybe someone here can point me what I'm doing wrong.
So for the explanation:
I have a DLL.
In it I have 2 classes:
class Plugin {
public:
Plugin() : isInited(false) { all_plugins.push_back(this); }
virtual ~Plugin() { }
virtual int OnInit(ONINIT_PARAMS) { return 0; }
virtual void OnDeInit(ONDEINIT_PARAMS) { }
virtual int OnTick(ONTICK_PARAMS) { return 0; }
private:
static std::vector<Plugin*> all_plugins;
private: // NO COPY CLASS
Plugin(const Plugin&);
const Plugin& operator=(const Plugin&);
};
This class is responsible for mapping the Init/DeInit/Tick function-calls which comes from the main application.
Secondly I have this:
class DynamicModule {
public:
DynamicModule() : isLoaded(false) { all_modules.push_back(this); }
virtual ~DynamicModule() { }
virtual int OnLoad() { return 0; };
virtual int OnUnload() { return 0; };
private:
static std::vector<DynamicModule*> all_modules;
private: // NO COPY CLASS
DynamicModule(const DynamicModule&);
const DynamicModule& operator=(const DynamicModule&);
};
#define IMPLEMENT_DYNAMICMODULE std::vector<DynamicModule*> DynamicModule::all_modules;
Now in plugin.cpp I do:
IMPLEMENT_DYNAMICMODULE;
std::vector<Plugin*> Plugin::all_plugins;
That takes care of the static stuff.
Now I define a class (in a header file):
class InMarket : public Plugin {
public:
int OnInit (ONINIT_PARAMS);
void OnDeInit(ONDEINIT_PARAMS);
int OnTick (ONTICK_PARAMS);
private:
};
And implement it in a C++ file:
static class InMarket _InMarket;
I traced it, and the constructor gets called correctly. And inserted into Plugin::all_plugins.
Then I continue tracing, and I see the modules (2 at the moment, defined for example like the next example [in a C++ file]):
static class MQL4Trade : public DynamicModule {
public:
virtual int OnLoad() {
__OrderSend = (_OrderSend)GetProcAddress(exe, "OrderSend");
__OrdersCount = (_OrdersCount)GetProcAddress(exe, "OrdersCount");
return 0;
}
} _MQL4Trade;
I see these modules get inserted as well nicely in DynamicModule::all_modules.
But at the same time when I see this, I also noticed the Plugin::all_plugins has a {size=0}?!
Then when I enter my OnInit() function, I see that all_modules has a size of 2, and all_plugins = 0. Even though ALL of the constructors had been called?
I load my library as:
HMODULE plugin = LoadLibrary(pluginFilename.c_str());
All static objects constructors are called....
And I don't see ANY differences between the 2 things.
What is going on here?
Using the following two classes...
//pure virtual...
class Monkey
{
public:
virtual ~Monkey(){}
virtual void clearMonkeys() = 0;
virtual std::shared_ptr<std::vector<sf::Text>> getMonkeyListPtr() = 0;
virtual void addMonkey(String message,Vector2f position,float depthValue) = 0;
};
class NullMonkey : public Monkey
{
public:
NullMonkey () {/*Do Nothing*/}
virtual ~NullMonkey () {/*Do Nothing*/}
virtual void clearMonkeys(){/*Do Nothing*/};
virtual std::shared_ptr<std::vector<sf::Text>> getMonkeyListPtr()
{
//Do Nothing but...
//Return NULL shared pointer
std::shared_ptr<std::vector<sf::Text>> nullSharedPointer;
return nullSharedPointer;
//Of course I am ASSUMING I will check for NULL pointer...
}
virtual void addMonkey(String message,Vector2f position,float depthValue){/*Do Nothing*/};
};
...I have issues when casting.
Specifically I am using these classes as static members and have a situation where if one class is not available I use the Null class to fall back on to prevent app crash. It also adds the ability to hot-swap child classes for debug purposes.
Unfortunately the following...
class ServLoc
{
public:
ServLoc();
static void initialize()
{
theMonkey = &theNullMonkey; //Error here
}
//...
static Monkey* theMonkey;
static NullMonkey theNullMonkey;
};
...throws 'cannot convert NullMonkey* to Monkey* in assignment'.
I should also add add I have defined the static members in the .cpp file
NullMonkey ServLoc::theNullMonkey;
Monkey* ServLoc::theMonkey;
The funny thing is I have used similar classes in similiar situations before and did not get this error. I am at a loss. It is probably something simple but still...
In fact I implement a log class using this method. It means I can hot-swap various forms of logging (including the null logger to disable logging) and have access to the logger wherever by just using the ServLoc static members...
class Logger
{
public:
virtual ~Logger() {}
virtual void log(const logType type,const char *message) = 0;
//...
};
class NullLogger : public Logger
{
public:
virtual ~NullLogger() {/*Do Nothing*/};
NullLogger() {/*Do Nothing*/};
virtual void log(const logType type,const char *message) {/*Do Nothing*/};
//...
};
This when used in same way in ServLoc as shown above works fine!?
Any ideas?
Regards
Edit - Fixed spelling mistakes
I suspect (could you clarify?), that you are calling the static function initialize() from another statically initialized class? Since this would all be done at program startup (and C++ does not guarantee any static initialization order between files), initialize may be called before ServLoc::theNullMonkey; has been constructed?!
Is it possible to create an instance of a class on a heap without calling default constructor and with a valid vtable for inheritance? Let me demonstrate what I will like to do:
class A
{
protected: virtual void _fake_static_method()
{
}
};
class B1 : public A
{
protected: virtual void _fake_static_method()
{
std::cout << "Hello";
}
public: static void run_fake_static_method()
{
B1* dummy = static_cast<B1*>(::operator new(sizeof(B1)));
dummy->_fake_static_method();
free(dummy);
}
}
class B2 : public A
{
public: static void run_fake_static_method()
{
B2* dummy = static_cast<B2*>(::operator new(sizeof(B2)));
dummy->_fake_static_method();
free(dummy);
}
}
Here I want to call a static method from example B1::run_fake_static_method(). In that method I want to run a member method, but I don't want to call the default constructor. I need such an implementation to remove the virtual method without a compiling error among other errors. Like a "virtual static method" I hope you understand what I want to do.
Is there a special trick that I can get this to work? :)
I want to implement a pure virtual function of a shared lib and call it in a lib-function. This lib-function will be called in the constructor of the lib. The class which contains the pure virtual function is in an own namespace. It looks like this:
//shared lib class:
namespace A{
namespace B{
class SharedLibClass : public object{
public:
SharedLibClass(){init();}
protected:
virtual const object* func()const=0;
private:
void init(){const object* obj=func();}
}
}//namespace B
}//namespace A
//implementation class using the shared lib:
class B : public A::B::SharedLibClass
{
protected:
virtual void func(){return this;}
}
This are my classes. I can compile them without problems, but when I run it, Qt prints out the following error:
pure virtual method called
terminate called without an active exception
I could imagine the problem is, that the parent class calls the virtual function before it is initialised or something like that. How can I solve this problem?
You can't declare function void and then return something from it. And you need to declare your function with exactly the same signature if you want to make it implementation of existing pure virtual function:
class B : public A::B::SharedLibClass {
protected:
virtual const object* func() const { /* your implementation */ }
}
Any good compiler recognizes these issues in compilation time. Check error reporting, maybe something is wrong in your build process (maybe your file isn't compiled at all?).