C++对象模型:g++的实现(五)


1. 单一继承体系下的虚函数

在前面的博客中我们已经通过对虚表的探索讲了虚函数的一般实现,大体上来说就是编译器会在适当的时候(在单一继承体系中就是当类中第一次出现虚函数的时候)添加一个虚表指针,指向属于该类的虚函数表,而所有虚函数的地址会出现在虚表指针的固定表项,也就是说在继承体系下的一个虚函数会被赋予固定的虚表下标。当派生类覆写(override)了基类的虚函数时,新的虚函数的地址会出现在基类虚函数在虚表中的位置,在多态调用虚函数时从虚表中取出虚函数地址来调用,从而实现多态。
一般而言,在单一继承体系下每一个类都只有一个虚表,在这个虚表中存有所有active virtual functions(中文版《深度探索C++对象模型》没有翻译,我这里也直接使用了,在我的理解里就是派生类所有有效的、能用的虚函数)的地址。这些active virtual functions包括:

  • 该类所定义的所有虚函数,包括其覆写(override)的基类的虚函数;
  • 继承自基类的虚函数,如果派生类不覆写这些虚函数的话;
  • 一个pure_vairtual_called()函数实体,她既可以扮演pure virtual function的空间保卫者角色,也可以当作异常处理函数(有时候会用到)【《深度探索C++对象模型》原话】

 
  // test23.cpp
   
  class Base {
  public:
  Base(int i)
  : m_i(i)
  {}
   
  virtual
  ~Base() {
  m_i = 0;
  }
   
  virtual
  int getInt() {
  return m_i;
  }
   
  virtual
  void increaseInt() {
  m_i++;
  }
   
  virtual
  long getLong() = 0;
  private:
  int m_i;
  };
   
  class Derived: public Base {
  public:
  Derived(int i, long l)
  : Base(i),
  m_l(l)
  {}
   
  virtual
  ~Derived() {
  m_l = 0;
  }
   
  virtual
  int getInt() override { // overrid Base::getInt()
  return Base::getInt() + 1;
  }
   
  virtual
  long getLong() override { // overrid Base::getLong(),在Base中是一个纯虚函数
  return m_l;
  }
   
  virtual
  void increaseLong() { // new virtual function
  ++m_l;
  }
  private:
  long m_l;
  };
   
  int main() {
  Derived* pd = new Derived(1, 2L);
  int i = pd->getInt();
  pd->increaseInt();
  long l = pd->getLong();
  pd->increaseLong();
  pd->~Derived();
  delete pd;
  }

另外,在这里我们可以注意到一个问题,虚表指针指向的空间,前两个表项都显示是Derived::~Derived(),也就是都是析构函数,而且地址不一样,这是怎么回事?我们看一下这两处地方的汇编代码
可以看到,第一个析构函数就是普通的析构函数它先调用了我们自己定义的析构函数,再调用了基类的析构函数Base::~Base;而第二个虚构函数则是先调用了第一个析构函数,再调用了::operator delete(_ZdlPvm使用c++filt工具查看可知其就是operator delete(void*, unsigned long))。
那是不是就是当我们自己调用Derived::~Derived时调用第一个,使用delete操作符时调用的就是第二个呢?我们看到反汇编
可以看到确实是这样的。同时,我们还有一个小发现,就是当delete操作符操作的指针是nullptr时,是不会调用析构函数的,编译器真是相当费心了(在我的测试下好像是只有delete一个指向有虚析构函数的对象的指针时才会检查,否则就直接不检查调用::operator delete)。

本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;

2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;

3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;

4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;

5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/java/293355.html

(0)
上一篇 2022年11月21日 17:59
下一篇 2022年11月21日 19:52

相关推荐

发表回复

登录后才能评论