C++:动态虚函数调用

发布于 2024-09-30 07:49:47 字数 1219 浏览 4 评论 0原文

我正在寻找动态调用虚函数的解决方案。这意味着在运行时支持带有偏移量和动态类型的函数调用。

我正在为一个游戏开发一个插件(《反恐精英:来源》,如果你知道的话)。插件接口不太可能,因此您无法像大多数人想要的那样扩展。为了实现更好的通信和操作游戏的方式,我支持调用虚函数。例如,CCSPlayer 类具有这些方法:

Offset    Name
...
201       CCSPlayer::Ignite()
...
205       CCSPlayer::CommitSuicide(bool Blah)
...
250       CCSPlayer::SomeFunctionWith2Params(int A1, float A2)

将这些偏移量和指向此类实例的指针传递给我当前的函数(见下文),我可以调用此函数:

CBasePlayer *pPlayer = Players.Find("mike");
bool bResult = Call2<bool, int, float>(210 /* offset */, pPlayer, 20, 50.0f);

我这样做是为了调用我无法通过正常调用的虚函数因为编译器不知道派生的 CCSPlayer 类的结构。

现在我想添加一种具有动态虚函数调用的脚本语言。这意味着,脚本编写者可以设置参数的数量及其类型。然后将 this 指针和偏移量传递给函数,最终执行它。这是我真正的问题。

目前,我只能通过使用模板并为每个参数创建一个函数来对它们进行硬编码。例子:

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);
}

现在有没有可能支持动态调用?

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 there any possibility to support dynamic calls?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清风夜微凉 2024-10-07 07:49:47

这太破了,很难考虑扩展它。

您不处理虚拟继承。您甚至不处理多重继承。

虚函数不能表示为单个“偏移”整数。您需要接受指向成员的指针参数。

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.

浅语花开 2024-10-07 07:49:47

正如另一位发帖者所说,在 C/C++ 中没有执行此操作的本机方法。

但是,您可能有兴趣研究 FFCALL 库,或更具体地说 avcall。该库允许您构建参数列表,然后对其调用函数。

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.

≈。彩虹 2024-10-07 07:49:47

没有内置的方法来生成排列。我想您可以使用一些库,但我建议编写一个小程序来为您生成所有模板。这使您可以完全控制生成的源代码,其中没有无关的垃圾,并且很容易单步执行。

所提出的方法的一个问题是,所指向函数的参数类型是从提供的参数中推导出来的。参数类型确实应该独立指定。就目前情况而言,您可以(比如说)将浮点数传递到需要 int 的函数中,并得到无效的结果(最多)。来电者必须非常准确地表达自己的价值观!如果您有源代码生成程序,您可以稍微调整它以生成转发函数,大致如下:

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);
}

等等,无限(或不远)。

当然,这并不是非常方便。并且它生成了很多函数。但是,如果您要将其公开给脚本语言,则无论如何您都需要为每种参数类型组合提供一个函数......

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...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文