探索C++多态和实现机理

内容预览:
  • 前一段时间被问到过一个问题,当时模模糊糊,就是说不清楚,问题问到说...~
  • 它是一块虚函数的地址表,通过一块连续内存来存储虚函数的地址~
  • 结束标识在不同的编译器下可能会有所不同~

前一段时间被问到过一个问题,当时模模糊糊,就是说不清楚,问题问到说:什么情况下会将基类的析构函数定义成虚函数?

  当时想到 如果子类B继承了父类A,那么定义出一个子类对象b,析构时,调用完子类析构函数,不是自动调用父类的析构函数吗!干嘛还要把定义为虚函数。将基类析构函用到了数定义成虚函数,难道是也是为了实现多态?。。  额,现在想想,其实自己都想到多态了,可惜还是没加点劲想到点上。这个问题用到了多态的原理。因为鉴于父子类的析构函数底层其实是同名(编译器做了特殊处理,都叫destructor),那么它们便构成重写,达到了多态的条件;如果基类析构不是虚函数,构不成多态,但是却要去删除一个指向派生类的基类指针时,此时函数按类型调用,于是便会只调用基类析构,未调用子类析构函数而产生内存泄漏。如


  1 #include<iostream>

2 using namespace std;
3
4 class A
5 {
6 public:
7 ~A()
8 {
9 cout<<"~A()"<<endl;
10 }
11 protected:
12 int _a;
13
14 };
15 class B:public A
16 {
17 public:
18 ~B()
19 {
20 cout<<"~B()"<<endl;
21 }
22 private:
23 int _b;
24 };
25 int main(void)
26 {
27 A* p = new B;
28 delete p;
29 return 0;
30 }

例:

 按《Effective C++》中的观点其实是:只要一个类有可能会被其它类所继承, 析构函数就应该声明是虚析构函数。

那为什么定义成虚析构函数就能解决这个问题呢?

    因为实现了多态。这样父类的指针/引用 调用重写的虚函数,当父类指针/引用指向父类对象时调用的是父类的虚函数,指向子类对象时调用的是子类的虚函数;所以析构函数被定义为虚函数就不难理解了。

那多态底层又是怎么实现的呢?来探索一下。

多态底层实现

多态实现利用到了一个叫虚函数表(虚表V-table)的东西。它是一块虚函数的地址表,通过一块连续内存来存储虚函数的地址。这张表解决了继承、虚函数(重写)的问题。在有虚函数的对象实例中都存在一张虚函数表,虚函数表就像一张地图,指明了实际应该调用的虚函数函数

Vs2008下,虚表(v-table)大致是这样,

简化后就像这样

                               

 

注意 :

     ①每个虚表后面都有一个‘0’,它类似字符串的‘

0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论