Sign in to follow this  
quaker

Extending a C++ class at runtime????

Recommended Posts

quaker    100
Hello I'm trying to find a way to link at run time to a class implemnetation. It's like this: I have a class, lets say AAA with function foo implented and compiled in an exxutable module. The class AAA is to be extended by another class BBB in a dynamic link library module and be able to use/inherit the AAA implentation of memebr function foo. It could be done in C as there by passing pointers to the function foo at run time, but this if could be done in C++ somehow will break the rule of many C++ features and it will become useless to use C++. Is there a way to do this like exporting virtual tables so that the BBB class can link to the functions in AAA? BTW I have looked at a similar thing in the game Sin source code which uses plain C for the core engine and the game code which is C++ is passed pointer to the C function at runtime. But what I want is a way to keep everything C++ and link at runtime. Thanks.

Share this post


Link to post
Share on other sites
Helter Skelter    332
Quote:
Original post by quaker
I have a class, lets say AAA with function foo implented and compiled in an exxutable module. The class AAA is to be extended by another class BBB in a dynamic link library module and be able to use/inherit the AAA implentation of memebr function foo.



You'll need to place AAA into a shared library (DLL) and include the necessary import/export declaration in the class declaration as such:


#ifdef CREATE_AAA_DLL
#define AAA_EXPORT __declspec(dllexport)
#else
#define AAA_EXPORT __declspec(dllimport)
#endif

class AAA_EXPORT AAA {


};



This will instruct the compiler to export the attributes, methods, and vtable of AAA (with full C++ name mangling) in the DLL.

Share this post


Link to post
Share on other sites
quaker    100
And then?

This works if you want to link statically with a library, or at runtime but you need to create an object first to access the methods.

My question is much more complex and I've been thinking about it for too long trying to find a reliable and practical solution that does not affect the main C++ purpose.

Share this post


Link to post
Share on other sites
Sneftel    1788
And then you write a creator function. That's the entry point the host application will use to instantiate your class even without knowing its name.


__declspec(dllexport) class BBB : public AAA
{
public:
virtual void foo() { ... }
};

__declspec(dllexport) AAA* Create()
{
return new BBB;
}

Share this post


Link to post
Share on other sites
Sneftel    1788
Oh, and then in your host application you do something like this:


AAA* CreateSubclassOfAAA(const std::string &name)
{
HMODULE hmodule = LoadModule((name + ".dll").c_str());
AAA*(*creator)() = GetProcAddress(hmodule, "Create");

return creator();
}

Share this post


Link to post
Share on other sites
quaker    100
Thanks. but this is not what I'm asking about.

//inside the excutable module EXE

class AAA {

void foo();

}

void AAA::foo() {
......
}

//inside a dll module

class BBB : public AAA {

void myfoo();
}

BBB::myfoo()
{
foo(); // call AAA's foo implemntation first
.....
}

Then the EXE file use your suggestion to make instances of BBB ok I know that, but how to get AAA::foo() implemntation at runtime whether it's declared virtual or not?

Share this post


Link to post
Share on other sites
Boku San    428
quaker: Not sure I understand the last post.

Fruny's method returns a pointer to a derived type -- a pointer to a base class (AAA) should be easy to cast into the derived class (BBB), should it not?

Therefore, calling class AAA's Create() method will, depending on the DLL linked, generate a correct instance flawlessly.

I think that's how it all should end up working, even though I don't understand the OP.




DISCLAIMER: Nothing in this post is guaranteed to be true or even well-informed.

EDIT:
Quote:
but how to get AAA::foo() implemntation at runtime whether it's declared virtual or not?
Hmm...if AAA::foo() is declared virtual, it may be overwritten by the generated instance of BBB.

This is how I'd try implementation:

AAA* base = new AAA;
//decide which DLL to load, determining implementation of class::foo()
...
base = Create(); //generate a new instance of that class
//base is now, in Fruny's example, a "new BBB"
base->foo(); //calls BBB::foo()



But, as with all technical answers I attempt to mess up, don't quote me on that. Unless somebody smart comes along and says "Yes, that's right, and it's a correct way to use interfaces to write extensible code. You're so awesome, Boku San." Then you can touch quote me.

EDIT AGAIN AFTER ACTUALLY READING THE LAST POST: Also, if you're looking to extend a class generically (google "interfaces"...or something like that), you won't want to add any methods to extending classes (BBB) -- instead, rename BBB's myfoo() to simply foo() and allow it to call AAA::foo(), if it's necessary.
(...I gotta stop editing)

Share this post


Link to post
Share on other sites
quaker    100
Look at the Sin source code thoroughly and you will get my question.

But this source is not pure C++ since the engine part which originally a Quake 2 engine written in plain C. But the game code/logic/entities is C++ calling core engine functionalities through pure C calls.

But this is not purely OO approach.

Share this post


Link to post
Share on other sites
quaker    100
Ah and doing it as you suggest:

BBB::myfoo() {
base->foo(); // this will invoke the intended function on the wrong object
// it's not called for (this) object of BBB
.......

}

Share this post


Link to post
Share on other sites
mattnewport    1038
You need to use implicit linking if you want to call non-inline functions from a separate dll like that. Sneftel's example uses explicit linking where you use GetProcAddress() to get the function by name. With implicit linking you have a .lib file which you statically link which contains stub functions which forward to the dll at runtime. In this case your base class would have to be defined with exported functions and your derived class would link statically to the import library created when you build the base class module. If you export functions from your main executable the linker will create an import library for the exe so you don't necessarily need to break your base class out into a separate dll for this to work. When you use implicit linking the runtime handles loading the dlls for you automatically so there's no need to call LoadLibrary() or GetProcAddress(). Search MSDN for 'linking dll' and you should turn up the info you need.

Share this post


Link to post
Share on other sites
mattnewport    1038
I wanted to test out how this works for myself (we don't use dlls often at work and I'm a bit rusty on the details) so I put together a little test project (VC .NET 2003). It shows how to do what I think you are trying to achieve. A few things to look out for when using dlls with C++:

- Be careful of allocating memory in one module and freeing it in another. This should be safe as long as all modules link to the multi-threaded dll versions of the runtimes. If you leave the default setting of linking to the non-dll versions of the runtimes you'll have big problems. Another option is to have create and delete functions in the dll and to avoid allocating memory in one module and freeing it in another completely.

- You can run into cross-dll memory problems even if your own classes do not pass memory ownership across modules if you use the standard libraries. The simplest answer is just to always use the multi-threaded dll runtime libraries if you use dlls anywhere.

- Be aware that inline functions will typically be expanded inline in the module that is importing a dll if it includes the header. This can sometimes cause problems.

- If you want to explicitly link to functions exported by a dll (like the create function in my example) you may want to declare them as extern "C" since otherwise they will have mangled names and you'll have to find out what the mangled name is in order to use GetProcAddress().

Share this post


Link to post
Share on other sites
quaker    100
Thanks.

I already know all that stuff related to dynamic linking. But what you have shown is a way to allow a module to use another (object/instance of the class) and not the class itself defined in a different module. It's more a plugin mechanism to substitute C function pointers.

My question again, though I doubt now any can solve it:

I want to link to the definition of core/base fuctionality of a class defined in an (EXCUTABLE) module at run time so that derived classes in another module can inherit from it as if they were compiled into single EXE.

Share this post


Link to post
Share on other sites
mattnewport    1038
Quote:
Original post by quaker
I want to link to the definition of core/base fuctionality of a class defined in an (EXCUTABLE) module at run time so that derived classes in another module can inherit from it as if they were compiled into single EXE.

Hmm, I think that's exactly what my example shows unless I'm misunderstanding you. In my example the code for base::f() lives in the exe. The code for derived::g() lives in the dll. The derived class inherits from the base class and when derived::g() is executed it calls the function base::f() and executes the code for base::f() that lives in the exe. That seems to be what you want, if it's not perhaps you can clarify further exactly what you mean?

Share this post


Link to post
Share on other sites
Helter Skelter    332
Quote:
Original post by quaker
I want to link to the definition of core/base fuctionality of a class defined in an (EXCUTABLE) module at run time so that derived classes in another module can inherit from it as if they were compiled into single EXE.



You've been given several suggestions all of which work for dynamically linking to the implementation base class. You can stick AAA in a DLL or you can place it in an executable. Both methods work and will create the proper import library so that the DLL containing BBB can access it and inherit from it.

I'm still puzzled as to why a complex problematic implementation is desired and why a much simpler easier to maintain approach is not satisfactory. Why is it so important to use the approach in Sin?

Share this post


Link to post
Share on other sites
quaker    100
Reagrding the source code you provided, mmmmm sorry it will never compile, the derived.cpp file. yes. why? because there's a declaration for f() existence in the base class without being implemented in the derived module which is supposed to be compiled independently.

Share this post


Link to post
Share on other sites
mattnewport    1038
Quote:
Original post by quaker
Reagrding the source code you provided, mmmmm sorry it will never compile, the derived.cpp file. yes. why? because there's a declaration for f() existence in the base class without being implemented in the derived module which is supposed to be compiled independently.

Did you actually try building it? The project builds and runs perfectly fine. I don't think you've quite understood the concept of an import library. When you declare a class as __declspec(dllexport) in a module the linker creates not only the module but also a .lib file - the import library. The import library does not contain the functions themselves, it contains stub functions and initialization code. Other modules that want access to functions exported from the module link to the import library (this is the implicit linking I was talking about earlier and which is described in the MSDN article I linked to). Linking to the import library does not link in the function code, only the stubs. At runtime when the module is loaded the initialization code in the import library is executed which loads the necessary external modules (using LoadLibrary() or the equivalent) and sets up the jump table for the stub functions (effectively it goes through and calls GetProcAddress() for all the imported functions and builds a table of function pointers - much easier than trying to do it manually - the exact details are described in an article by Matt Pietrek somewhere online I think). Your code can then magically use those functions exported from the dll as if they were statically linked, it just has to link to the import library (as my example project does if you take a look at it).

Share this post


Link to post
Share on other sites
quaker    100
I know that. But I don't want to link statically to the import library. My goal is to be able to provide the client with a closed EXE file and being able to extend it through a dll.

Share this post


Link to post
Share on other sites
Boku San    428
Quote:
Original post by quaker
I know that. But I don't want to link statically to the import library. My goal is to be able to provide the client with a closed EXE file and being able to extend it through a dll.


Read the PM I sent you if you haven't already. (which, you know, you haven't. One solution is exactly what I described)

Share this post


Link to post
Share on other sites
mattnewport    1038
Quote:
Original post by quaker
I know that. But I don't want to link statically to the import library. My goal is to be able to provide the client with a closed EXE file and being able to extend it through a dll.

Why can't you provide the client with an import library? Your problem is exactly what this mechanism exists for. You could replicate all that work yourself (create your own import library with stub functions) but I'm not sure what the point would be.

Share this post


Link to post
Share on other sites
Helter Skelter    332
Quote:
Original post by quaker
I know that. But I don't want to link statically to the import library. My goal is to be able to provide the client with a closed EXE file and being able to extend it through a dll.


We don't think you're stupid but *I* personally think that you've gotten yourself so dead set on a prticular approach that you're unwilling to consider alternatives. This can happen to even the most experienced developers especially when they've invested a significant amount of time trying to make the approach work.

Now if I understand this correctly you want to do something similar to:

a = CreateFromBaseClass(); // In your EXE
b = CreateFromChildClass(); // In the users DLL
c = MergeFromObjects(a, b); // new kind of object

a has no idea about b (which is a good thing)
b has no idea about a (this is bad)


In that case what you are wanting is not impossible to do in C++ but extremely impractical especially if your intention is to retain a pure OO implementation. With C++ being a statically typed language many of the implementation details for dealing with inheritence, virtual methods, virtual base classes, and instantiation are handled by the compiler and/or the runtime libs.

The problem is that C++ (the language) does not provide support for dynamic types at runtime. There are certain design patterns that can be applied such as Factory to provide "virtual constructors" but that's about as close as you're going to get.

It also sounds like your intention is to remove all knowledge of the base class so prevent users from directly instantiating object of that type and/or requiring that they implement specific methods/functions. If that's the case you can still impose the same restrictions using pure virtuals. Fiddling with an expected layout of a class can have unexpected side effects. Problems with scalar destructors, unintentional memory corruption, breaking exception handling, and very possibly calling the incorrect method.

If you take a look at technologies that allow (to an extent) dynamic runtime classes you will notice certain restrictions that if allowed would break the overall implementation. Java's single inheritence of classes (multiple interfaces) and COM (usually) requiring pure interfaces (no data, no concrete methods) both come to mind. Even in Java you still have to know (in some way) about the base class or interface even though binding it done at runtime. Java also has a good reflection package. Languages that allow this type of dynamic typing (Objective-C for example) usually impose additional overhead as a result. That overhead is not much but IS there and handled by the compiler and runtime.

IF your base class (AAA in the example) has no implementation (all pure virtual functions) or data declare the class as having no vtable. This will prevent the compiler from automatically generating default constructors and destructors and removes the default vtable.

IF your base class DOES have implementation or data you seriously need to rethink your approach. Even if you do succeed in what you are trying to do tracking down any bugs that it creates may be significantly difficult.

Share this post


Link to post
Share on other sites
Helter Skelter    332
Quote:
Original post by mattnewport
Why can't you provide the client with an import library? Your problem is exactly what this mechanism exists for. You could replicate all that work yourself (create your own import library with stub functions) but I'm not sure what the point would be.


After going back and rereading all the posts it sounds to me like he's attempting to do dynamic runtime class declarations. Chances are the Sin game engine is instantiating the base class, manually building the vtable, and then allowing new virtuals and attributes to be added to the object after the fact.

Share this post


Link to post
Share on other sites
quaker    100
I'm gradually getting to your points all. I thought there should be some secret I still don't know about to access virtual tables and fill them with appropriate function pointers at runtime. Maybe this should be considered in future specification of C++ or as an extended capability of a compiler.

Actually I was wondering why most if not every game developer tends to use C++ which imposes more restrictions and less flexibility which is needed in creating a fast customizeable engines.

I bleive the success of Quake series engines is that they are pure C. They are damn fast. What about the overhead of using try catch statments?

My belife is that C++ more suits general applications that don't require real-time interactivity such as games.

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

Sign in to follow this