Jump to content
  • Advertisement
babaliaris

C++ Amazing Idea went wrong: Creating polymorphic Methods among DLL and Client!

Recommended Posts

There are two projects. One is called VampEngine (a Shared Library) and the other Application (A console application).

The VampEngine contains a VampEngine::Core class. This function contains a void VampEngine::Core::MainLoop() method.

There are also two extern C functions void *Vamp_Core_Constructor() and Vamp_Core_MainLoop(void *obj)

Now, this is what happens:

The client is calling void *Vamp_Core_Constructor() in order to create a VampEngine::Core which lives inside the Shared Library. And also casts this void object into a Core object.

The void VampEngine::Core::MainLoop() is being implemented both in the Shared Library and in the client. The client's MainLoop() is just a wrapper for calling the extern c function Vamp_Core_MainLoop(void *obj)

The code compiles and links in both Windows and Linux. When you run it on Windows, MainLoop() (shared library's implementation) is getting called, but on Linux, there is a recursive call in the client's MainLoop() implementation.

The behavior in each Operating System can be shown below:

Untitled-Diagram.jpg

asd.jpg

You can check the project (It's small, I just started it ) On my GitHub Repo . Also, I have a Premake script if you want to check the code for yourself. You are most interested in the files:

API.h  EntryPoint.h  Application.hpp  Core.cpp  Core.h  Core.hpp  Main.cpp

 

 

This might explain the problem in a better way:

The Core class has two implementations of the Core::MainLoop(). One is implemented inside the DLL and the other in the client. The client's implementation is just a wrapper which calls a c extern function (which lives in the dll) which actually calls the MainLoop() implemented inside the DLL. 

Now in visual c++, because I'm only exporting that c extern function, Core::MainLoop() acts in a polymorphic way. The client calls his implementation of Core::MainLoop() which calls the extern function and eventually the Core::MainLoop() inside the dll runs.

On linux, I believe by default all the symbols are getting exported. And this is the behavior I saw using a debugger:

The client calls Core::MainLoop() , this calls the extern function, the extern function calls again Core::MainLoop() but instead of running the dll implementation it actually runs the the clients implementation. It's like the clients Core::MainLoop() is calling itself over and over again!

 

Conclusion:

I located the above behavior using gdb debugger on Linux. I just noticed the client's implementation was getting called in a recursive way instead of acting polymorphically ending up calling the implementation of the dll's MainLoop()

Edited by babaliaris

Share this post


Link to post
Share on other sites
Advertisement

What's the point of returning void* here if your client application has to cast to Core* anyways?

void * Vamp_Core_Constructor(const char* title, unsigned int width, unsigned int height)

As for your problem, your client contains

namespace VampEngine
{
	void Core::MainLoop()
	{
		Vamp_Core_MainLoop((void *)this);
	}
}

but your .dll also has this method defined

namespace VampEngine
{
	void Core::MainLoop()
	{
		/* omitted */
	}
}

For reasons unknown to me linked does not see this as a problem when 2nd method is inside .dll and just chooses any of them, which happens to be a different method on Windows and Linux. If you try to build your .dll as static library the problem becomes apparent:

2>VampEngine.lib(Core.obj) : error LNK2005: "public: void __cdecl VampEngine::Core::MainLoop(void)" (?MainLoop@Core@VampEngine@@QEAAXXZ) already defined in Main.obj

 

Edited by Zaoshi Kaba

Share this post


Link to post
Share on other sites

Yes that's the problem, but I wasn't getting any "Already Defined errors". The thing is that on Windows it was actually working, probably because visual c++ was assigning a different name for the implementation into the dll and a different in the clients right?

Now on Linux, stackoverflow told me that gcc had to choose between those two implementations and it was choosing the clients implementation.

I found the solution to my problem though. I will create a CoreImpl class into the dll and a Core class in the client. The client will then create a Core object which it's constructor will actually call a c function (factory function or how it is called) to construct a CoreImpl object inside the dll. Then the Core class will have the appropriate wrapping methods which with the use of c functions and a CoreImpl object reference, will call any CoreImpl method.

Edited by babaliaris
Misspelled a word

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!