0

我最近一直在绕弯路编程,以及随之而来的一切。我绕了很多不同的功能;thiscall、stdcall、cdecl、虚函数等。但是有一件事我没有管理(这甚至可能是不可能的),那就是挂钩一个基类虚函数。例如; 有一个 Car 类,它声明了一个虚函数(空)Drive。然后还有其他 3 个 car 类继承了 car 和 implements Drive

如果我挂钩 Car 的(基类)Drive函数(使用简单的 'jmp' 挂钩),如果他们调用基函数,它会在触发时由 的后代Car触发吗?Drive

更彻底地解释:

class Car
{
   virtual void Drive(void) { } // Empty virtual function
}

class Lamborghini : public Car
{
   void Drive(void) { // does lots of stuff, but does NOT call base function }
}

所以我想知道是否调用了基本方法 get 或者是否可以以某种方式挂钩?函数执行是直接跳转到Lamborghini::Drive还是以某种方式通过Car类,以便在后代调用时可以检测到Drive

编辑:如果基类函数为空,是否甚至可以挂钩它,因为它需要 5 个字节的空间?

4

3 回答 3

5

不,基本方法不会被自动调用。动态调度机制将检测它需要调用哪个覆盖,这将是被调用的函数。这通常通过一个虚拟表 (vtable) 来实现,该表存储指向类中每个虚拟函数的最终覆盖器的指针。当使用动态分派时,编译器通过该表注入一个间接调用并跳转到正确的函数。

请注意,vtable 实际上包含指向thunktrampolines的指针,这些指针可能会this在转发调用之前进行修改(隐式第一个参数)。使用这种方式的好处是,如果this不需要更新,编译器可以直接跳转到最终的覆盖器中。无论如何,您可以利用此功能并修改 vtable 以指向您自己的代码(即您可以更新每个 vtable 中的指针——每种类型一个——以引用您自己的thunk函数

于 2012-05-08T12:33:07.900 回答
0

如果我正确地回答了您的问题,您的兰博基尼类中的 Drive 方法将根据虚函数表被调用。如果要调用基类的 Drive 方法,则必须编写类似Car::Drive;. 由于 VTBL,基类需要一些空间。希望我没有回答你的问题。

于 2012-05-08T12:32:50.543 回答
0

如果我理解正确的话,你想Car::Drive每次调用都Lamborghini::Drive被调用,即使Lamborghini:Drive不直接调用基函数?

为此,最简单的方法是使用“内部”函数,该函数将是虚拟的(受保护的),而初始方法将是非虚拟的,并将路由调用。这是一个例子:

class Car
{
    void Drive(void)
    {
        // ...
        Car::innerDrive(); // Base function call
        // ...
        this->innerDrive(); // 'Derived' function call
        // ...
    }
protected:
    virtual void innerDrive(void) { } // Empty virtual function
}

class Lamborghini : public Car
{
protected:
    void innerDrive(void) { // does lots of stuff, but does NOT call base function }
}
于 2012-05-08T13:23:14.480 回答