精简版
我正在使用特定对象的 vtable 中的条目来调用从接口继承的虚拟方法。最后,我正在寻找一种方法来获取每个地址到虚拟方法在特定对象的 vtable 中的确切偏移量。
详细版本
免责声明
我知道这个主题是依赖于实现的,并且不应该尝试手动执行此操作,因为编译器会执行(正确的)工作,并且 vtable 不被视为标准(更不用说数据格式了)。我在此作证,我已经阅读了数十篇“不要这样做......只是,不要这样做!”并且清楚我的行为可能产生的令人发指的后果。
因此(并有利于进行建设性的讨论)我将使用g++ (4.x.x)
Linux x64 平台上的编译器作为我的参考。使用以下代码编译的任何软件都将使用相同的设置,因此就这一点而言,它应该是平台无关的。
好的,我的这整个问题完全是实验性的,我不想在生产代码中使用它,而是为了教育我自己和我的同学(我的教授问我是否可以写一篇关于这个主题的快速论文)。
我要做的基本上是使用偏移量自动调用方法来确定调用哪个方法。类的基本大纲如下(这是一个简化,但显示了我当前尝试的组成):
class IMethods
{
virtual double action1(double) = 0;
virtual double action2(double) = 0;
};
正如您所看到的,只有一个具有共享相同签名的纯虚拟方法的类。
enum Actions
{
actionID1,
actionID2
};
枚举项用于调用适当的方法。
class MethodProcessor : public IMethods
{
public:
double action1(double);
double action2(double);
};
故意省略了上述类的ctor/dtor。我们可以放心地假设这些是从接口继承的唯一虚方法,并且多态性是无关紧要的。
基本概要到此结束。现在进入真正的主题:
是否有一种安全的方法可以将 vtable 中的地址映射到继承的虚拟方法?
我想做的是这样的:
MethodProcessor proc;
size_t * vTable = *(size_t**) &proc;
double ret = ((double(*)(MethodProcessor*,double))vTable[actionID2])(&proc, 3.14159265359);
这工作正常并且正在调用action2
,但我假设指向的地址等于索引 1 并且这部分让我感到困惑:如果在定义action2
地址之前在 vtable 中添加了某种偏移量怎么办?action1
在一本关于 C++ 数据对象模型的书中,我读到通常 vtable 中的第一个地址通向RTTI (runtime type information)
,作为回报,我无法确认,因为vTable[0]
它合法地指向action1
.
编译器知道每个虚拟方法指针的确切索引,因为,是的,编译器正在构建它们并用增强代码替换虚拟方法的每个成员调用,该代码等于我上面使用的代码 - 但知道要使用的索引。我这一次接受了有根据的猜测,即在我定义的虚拟方法之前没有偏移量。
我不能使用一些 C++-Hack 让编译器在编译(甚至运行)时计算正确的索引吗?然后我可以使用这些信息为我的枚举项添加一些偏移量,而不必担心投射错误的地址......