2011-10-21

VC和BCB那点事——虚函数的顺序问题

因为工作需要,编写了一个C++类,供一个VC下的DLL使用。用法类似回调对象,将C++对象的指针传给DLL导出的函数。类里面要被用到的函数全是虚函数,父类是个彻底的抽象类,由DLL的开发人员提供.h头文件。VC和BCB在虚函数表的实现上是一致的,因此可以跨模块调用。

大部分虚函数的调用测试都很顺利,但在一个函数上遇到了麻烦。不,应该说是两个。在测试过程中发现,当DLL想要调用我提供的C++类的FunA函数时,总是错误地调用到了FunB函数。反过来也一样,结果就好像是DLL把A函数和B函数搞反了。
class A
{
    ……
    virtual FunA() = 0;
    virtual FunB() = 0;
    ……
};
既然是按照虚函数表来调用,那就跟函数名无关。这一点很快就得到了证实。现在唯一剩下的就是顺序问题。根据资料,虚函数表里面的顺序是根据函数的声明顺序来排布的,也就是说.h头文件决定了顺序。调换了一下顺序,果然就正常了,可为什么会反呢?
其实不能只看这么一点儿代码,这个问题和上下文有关:
class A
{
    ……
    virtual FunB(int J) = 0;
    virtual FunA() = 0;
    virtual FunB() = 0;
    ……
};
最后是CSDN上一篇博文揭示了这个问题:VC会把重载函数给排在一起,不管中间有没有插队者。参见:http://blog.csdn.net/doudouhuy/article/details/4348531
也就是说,最终的顺序实际上是:
class A
{
    ……
    virtual FunB(int J) = 0;
    virtual FunB() = 0;
    virtual FunA() = 0;
    ……
};
而BCB大概不会做这个改动,因此调用到的函数就和预期的不一样了。

最后说一下。为了避免遇到类似问题,建议在进行跨模块的虚函数调用的时候,彻底避开重载函数出现的情况。把所有函数的名称都声明得不同,就不会轮到编译器来干扰了。

没有评论:

发表评论