C++ 虚函数表中的函数的索引

C++的虚函数表的结构在有析构函数和没有析构函数的情况下,还是有一定的区别的,主要区别如下:

首先是没有析构函数的情况,代码如下:

class test {
public:
  virtual void foo() {
    cout << "foo" << endl;
  }
  void moo(){
    cout << "moo" << endl;
  }
  virtual void goo() {t
    cout << "goo" << endl;
  }
  virtual void hoo() {
    cout << "hoo" << endl;
  }
};

当没有虚析构函数的情况,函数的索引是从上往下,0,1,2逐步递增的。

当类有了虚析构函数之后,索引就变了,示例代码如下:

class test {
public:
  virtual ~test() {
    cout << "~test" << endl;
  }
  virtual void foo() {
    cout << "foo" << endl;
  }t
  void moo(){
    cout << "moo" << endl;t
  }t
  virtual void goo() {
    cout << "goo" << endl;
  }
  virtual void hoo() {
    cout << "hoo" << endl;
  }
};

有了虚析构函数之后,foo的索引是变成了2。增加了一个析构函数,难道编译器会生成两个函数?于是使用clang编译器,使用命令:clang++ -emit-llvm  -fno-discard-value-names  -w -g  -S -o virtualtable.ll virtualtable.cpp 把代码编译成ll文件查看字节码进一步查看:

可以看到字节码如下,红色字部分,可以看到果然有两个析构函数:

@_ZTV4test = linkonce_odr dso_local unnamed_addr constant { [7 x i8*] } { [7 x i8*] [i8* null, i8* bitcast ({ i8*, i8* }* @_ZTI4test to i8*), i8* bitcast (void (%class.test*)* @_ZN4testD2Ev to i8*), i8* bitcast (void (%class.test*)* @_ZN4testD0Ev to i8*), i8* bitcast (void (%class.test*)* @_ZN4test3fooEv to i8*), i8* bitcast (void (%class.test*)* @_ZN4test3gooEv to i8*), i8* bitcast (void (%class.test*)* @_ZN4test3hooEv to i8*)] }, comdat, align 8

而且析构函数_ZN4testD0Ev中还调用了_ZN4testD2Ev。由此可以确定是有两个析构函数。

也可以使用测试代码测试一下虚函数的索引,代码如下:

int find_function_index(CMyTest* p, void* f) {
  for(int i = 0; i < 3; ++i) {
    void* tmp = (void*)*((long*)*(int*)(p)+i);
    if(tmp == f)
      return i;
  }
  return -1;
}

typedef void(* func)(void);

int main() {
  test* p = new test();

  void* f1 = reinterpret_cast<void*>(&test::foo);
  cout << "foo: " << find_function_index(p, f1) << endl;

  void* f2 = reinterpret_cast<void*>(&test::goo);
  cout << "goo: " << find_function_index(p, f2) << endl;

  void* f3 = reinterpret_cast<void*>(&test::hoo);
  cout << "hoo: " << find_function_index(p, f3) << endl;
  
  void* f4 = reinterpret_cast<void*>(&test::moo);
  cout << "moo: " << find_function_index(p, f4) << endl;
  
  func f6;
  f6 = (func)*(int *)((char*)(*(int *)p));
  cout << "descontructor: " << find_function_index(p, f6) << endl;
  f6();
  
  delete p;
}

编译执行代码,可以发现,无论析构函数的声明放在类的什么位置,它在虚函数表里的位置总在最前面,也就是索引是0。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值