码迷,mamicode.com
首页 > 其他好文 > 详细

虚函数原理

时间:2015-09-22 07:45:44      阅读:213      评论:0      收藏:0      [点我收藏+]

标签:

虚函数表的数量与位置:编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。编译器将虚函数表存放在了目标文件或者可执行文件的常量段,即代码区

虚函数表指针(vptr)的数量与位置:如果1个类中存在一个虚函数,那么第一个地址永远都是指向虚函数列表的指针子类没有vptr,子类的虚函数存放在第一个父类的虚函数表的最后,如果有覆盖,则覆盖掉相应父类的虚函数

 

lass Base {
public:
  virtual void f() { cout << "Base::f" << endl; }
  virtual void g() { cout << "Base::g" << endl; }
  virtual void h() { cout << "Base::h" << endl; }
};

Base b;

 

虚函数表地址:(int*)(&b)

虚函数表 第一个函数地址,即f()地址: (int*)*(int*)(&b) 

g()地址:(int*)*(int*)(&b)+1

h()地址:(int*)*(int*)(&b)+2

 

注意:在虚函数表的最后有一个结点,这是虚函数表的结束结点,就像字符串的结束符“\0”一样,其标志了虚函数表的结束。

一般继承(无虚函数覆盖)

1)虚函数按照其声明顺序放于表中。

2)父类的虚函数在子类的虚函数前面。

技术分享

 

对于实例:Derive d; 的虚函数表如下:

技术分享

 

一般继承(有虚函数覆盖)

1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。

2)没有被覆盖的函数依旧。

技术分享

这样,我们就可以看到对于下面这样的程序,

Base *b = new Derive();
b->f();

由b所指的内存中的虚函数表的f()的位置已经被Derive::f()函数地址所取代,于是在实际调用发生时,是Derive::f()被调用了。这就实现了多态。

多重继承(无虚函数覆盖)

1) 每个父类都有自己的虚表。

2) 子类的成员函数被放到了第一个父类的表中,子类自己没有虚函数列表的指针。(所谓的第一个父类是按照声明顺序来判断的)

技术分享

对于子类实例中的虚函数表,是下面这个样子:

技术分享

 

多重继承(有虚函数覆盖)

三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样,我们就可以任一静态类型的父类来指向子类,并调用子类的f()了。 

技术分享

下面是对于子类实例中的虚函数表的图:

技术分享

虚析构函数的作用

class A
{
public:
  A(){cout << "In A constructor" << endl;}
  ~A(){cout << "In A destructor" << endl;}
};
 
class B : public A
{
public:
  B()
  {
    cout << "In B constructor" << endl;
    m_p = new char[10];
  }
  ~B()
  {
    cout << "In B destructor" << endl;
    if (m_p) delete [] m_p;
  }
private:
  char *m_p;
};
 
int main(int argc, char* argv[])
{
  A *p = new B;
  delete p;
  return 0;
}

输出结果:

In A constructor

In B constructor

In A destructor

并没有调用B的析构函数,new出来的内存没有及时回收造成内存泄漏。解决的方法是将~A()定义为虚析构函数,那么像其它虚构函数一样,~B()重定义(overridden)了~A(),这样指向派生类的指针就能根据运行时的状态调用B的析构函数了。这里又有一个问题:为什么还会调用A的析构函数呢?我只能理解为析构函数是一个特殊的函数,由系统维护其机制。

所以使用虚析构函数的目的是:为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。

 

虚函数原理

标签:

原文地址:http://www.cnblogs.com/qionglouyuyu/p/4827852.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!