C++: Dynamic virtual function call
I'm searching for a solution to call virtual function dynamicly. This means to support function calls with offsets and dynamic types at runtime.
I'm working on a plugin for a game (Counter-Strike: Source, if you know it). The plugin interface isn't likely and so you cannot extend as much as most people want. To realize a better way to communicate and manipulate the game, I support calling virtual functions. For example, the CCSPlayer class has those methods:
Offset Name
...
201 CCSPlayer::Ignite()
...
205 CCSPlayer::CommitSuicide(bool Blah)
...
250 CCSPlayer::SomeFunctionWith2Params(int A1, float A2)
Passing these offsets and the pointer to the instance of this class to my current function (see below), I can call this functions:
CBasePlayer *pPlayer = Players.Find("mike");
bool bResult = Call2<bool, int, float>(210 /* offset */, pPlayer, 20, 50.0f);
I do this to call virtual functions I cannot call through the normal routine because the compiler doesn't knows the structure of the derived CCSPlayer class.
And now I want to add a scripting language with dynamic virtual function calls. That means, the scripters can set the amount of params, and of what type they are. Then passing the this-pointer and the offset to the function, to finally execute it. This is my real questions.
Currently I can only hardcode those by using templates and creating a function for every amount of params. Example:
template<typename T, typename A, typename B> T Call2(int iOffset, void *pThis, A arg1, B arg2)
{
void **pVTable = *(void***)pThis;
void *pPointer = pVTable[_iOffset];
union
{
T (CVCallEmpty::*pCall)(A, B);
void *pAddress;
} Data;
Data.pAddress = pPointer;
return (reinterpret_cast<CVCallEmpty*>(*(void***)&pThis)->*Data.pCall)(arg1, arg2);
}
Now, is the开发者_如何学Cre any possibility to support dynamic calls?
This is so broken, it's hard to think about extending it.
You don't handle virtual inheritance. You don't even handle multiple inheritance.
A virtual function cannot be represented as a single "offset" integer. You need to accept a pointer-to-member argument.
As another poster said though, there is no native way of performing this in C/C++.
HOWEVER, you might be interested in looking into the FFCALL library, or more specifically avcall. This library allows you to build lists of parameters, and then call functions on them.
There's no built-in way to generate the permutations. You could use some library, I imagine, but I recommend writing a little program to generate all the templates for you. This gives you full control of what source code is generated, there's no extraneous junk in there, and it's easy to single-step.
One issue with the approach presented is that the parameter types for the pointed-to function is deduced from the arguments supplied; the parameter types should really be specified independently. As it stands, you could (say) pass a float into a function expecting an int, and get invalid results (at best). The caller will have to be very precise with their values! If you have your source code generating program, you could tweak it slightly to generate forwarding functions, along the lines of:
inline void call_vii(int vi,void *obj,int a0,int a1) {
Call2<void,int,int>(vi,obj,a0,a1);
}
inline float call_viff(int vi,void *obj,int a0,float a1,float a2) {
Call2<void,int,float,float>(vi,obj,a0,a1,a2);
}
And so on, ad infinitum (or not far off).
This isn't exactly terribly convenient, of course. And it generates a lot of functions. But if you're going to be exposing this to a scripting language, you'll need a function for each combination of parameter types anyway...
精彩评论