多态和抽象

Posted songliduo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了多态和抽象相关的知识,希望对你有一定的参考价值。

①多态的特点是,类中有虚函数。抽象的特点是,类中有纯虚函数。

②多态的基类可以实例化对象,抽象类不可以实例化对象。如果一个抽象类的派生类没有实现这个抽象类的纯虚函数,那么这个派生类也是个抽象类,也是不能实例化对象。

③析构函数不是虚函数会有什么影响?在下面程序中,B是A的派生类,有一个A*类型的指针new了一个B类型的对象。当delete p的时候,如果A和B的析构函数是虚函数,那么调用的就是B的析构函数,如果不是析构函数,那么调用的就是A的析构函数。

class A
{
public:
    A();
    virtual ~A();
}

class B : public A
{
public:
    B();
    virtual ~B();
}

int main()
{
    A* p = new B();
    delete p;
    return 0;
}

④虚函数表。这个比较难解释,但是理解了虚函数表,就理解了多态的用处。转自下面这个博客。

https://www.cnblogs.com/wangxiaobao/p/5850949.html

从例子入手,考察如下带有虚函数的类的对象内存模型:

技术分享图片
 1 class A {
 2 public:
 3     virtual void vfunc1();
 4     virtual void vfunc2();
 5     void func1();
 6     void func2();
 7     virtual ~A();
 8 private:
 9     int m_data1, m_data2;
10 }; 
11 
12 class B : A {
13 public:
14     virtual void vfunc1();;
15     void func2();
16     virtual ~B();
17 private:
18     int m_data3;
19 };
20 
21 class C : B {
22 public:
23     virtual void vfunc1();
24     void func();
25 private:
26     int m_data1, m_data4;
27 };
技术分享图片

注:在子类中出现与父类相同名称的变量和非虚函数不是最佳实践,这里是为了说明其内存结构。

其对象内存结构见下图。

技术分享图片

                                               *图片来源于侯捷老师

对其分析如下:

1. 每个含有虚函数的类在内存中多一根指针(vptr),见图中a,b,c对象中第一个位置,存储的是虚函数表(vtbl)所在的位置。

2. 虚函数表(vtbl)存储着所有虚函数的位置,由于其动态绑定特性,在覆写(override)后在子类中存储的虚函数位置与父类中不相同。

3. 分析上述代码, B继承A,所以A中的数据部分也被B继承下来,同时B添加上了自己的数据部分m_data3,加之vptr,组成了B左侧的内存布局。

  A中的虚函数vfunc1(),vfunc2()可以被覆写和动态绑定。

  所以在B中,vfunc1()被覆写,其vtbl中对应项指向了新的函数的位置(亮蓝色)。vfunc2()未被覆写,仍然指向原先位置(深蓝色)。

  C与B同理,vfunc1()被覆写,其vtbl中对应项指向了新的函数的位置(橘黄色)。vfunc2()未被覆写,仍然指向原先位置(深蓝色)。

非虚函数静态绑定,存储在单独的内存空间(code memory section,灰色函数部分),调用时把对象的this指针,传给一个invisible参数,以便确定谁在调用函数。

4. 调用虚函数的语句的C语言形式如图中下部分所示,其中n表示对应的函数在第几个位置(编译器在建立虚函数表的时候已知),从而实现动态绑定。

以上是关于多态和抽象的主要内容,如果未能解决你的问题,请参考以下文章

多态与抽象以及接口

多态抽象类魔术方法

ObjectOrientedProgramming - 面向对象的编程(多态抽象类接口)- Java - 细节狂魔

python 接口类抽象类多态

封装继承和多态

实现:抽象类和多态的实例