我加载了一个共享库(我不知道其来源)并使用IDA为其创建了标头。
/>是否与此不同?

class Tester {
    public:
    virtual void test();
    virtual void replay();
};


评论

我猜这取决于编译器吗?

我也认为它应该取决于编译器。

#1 楼

虚拟功能的顺序很重要。更改源代码中的顺序将更改生成的机器代码中的顺序。在您的示例中,两个源示例将生成不同的机器代码。

编辑:使用下面@tathanhdinh提供的示例代码,MSVC如下生成两个vtable:

;   COMDAT ??_7B@@6B@
CONST   SEGMENT
??_7B@@6B@ DD   FLAT:??_R4B@@6B@            ; B::`vftable'
    DD  FLAT:?bust@B@@UAEXXZ
    DD  FLAT:?test@B@@UAEXXZ
CONST   ENDS
;   COMDAT ??_7A@@6B@
CONST   SEGMENT
??_7A@@6B@ DD   FLAT:??_R4A@@6B@            ; A::`vftable'
    DD  FLAT:?test@A@@UAEXXZ
    DD  FLAT:?bust@A@@UAEXXZ
CONST   ENDS


请注意,两个vtable中成员函数指针的顺序不同。如前所述,虚拟函数在至少一个编译器中的顺序很重要。

评论


正常功能如何?

–user160368
16 Mar 22 '16 at 10:29

非虚拟成员函数不会影响类或其vtable在内存中的布局。链接器将确定函数体将位于的偏移量。

– JohnKällén
16-3-22在10:30

+我可以省略一个或多个虚拟函数声明吗?

–user160368
16 Mar 22 '16 at 10:35

您需要确保您未将vtable对齐。您可以忽略要反汇编的函数之后出现的任何虚函数声明。

– JohnKällén
16 Mar 22 '16 at 10:36

@JohnKällén感谢您的回答,但是在我看来,源代码中的订单虚拟功能会影响机器代码中的订单的想法并不直观。我很难相信C ++标准(甚至C ++ ABI)中的某个地方说了这一点,我认为它应该依赖于编译器。

– Ta Thanh Dinh
16-3-22在13:40



#2 楼

我不认为您的意思是使用相同的类名,如果不使用该类名,则可能会产生重新定义错误。
br />
#include <iostream>
using namespace std;
class A {
    public:
    virtual void test() { cout<<"class A test virtual function \n"; }
    virtual void bust() { cout<<"class A bust virtual function \n"; }
};
class B {
    public:
    virtual void bust() { cout<<"class B bust virtual function \n"; }
    virtual void test() { cout<<"class B test virtual function \n"; }
};
int main(void) {
    A *foo = nullptr;
    B *bla = nullptr;
    try{        
    foo = new(A);
    bla = new(B);
    foo->bust();
    bla->bust();
    delete foo;
    delete bla;
    } catch(...){
    delete foo;
    delete bla; 
    }
    return 0;
}


执行将导致

cl /nologo /Zi /EHsc /O1 /analyze /W4 *.cpp /link /release


#3 楼

由于我认为虚拟函数在源代码中的顺序不会影响它们在机器代码中的顺序,因此我尝试举一个反例。主要思想是首先给出基类vtable的布局

struct A
{
  void virtual test() {};
  void virtual replay() {};
}


,然后使用两个继承A的类,但它们具有不同的虚函数顺序:如果BC中虚函数的顺序影响了它们的机器代码顺序,则它们在相应vtables中的指针应该不同。但是以下生成的机器代码(我使用clang作为编译器)表明它们不是:

struct B : public A
{
  void virtual test() {};
  void virtual replay() {};
}

struct C : public A
{
  void virtual replay() {};
  void virtual test() {};
}


BC中虚函数的顺序确实相同(并尊重A中的一个)。