zoukankan      html  css  js  c++  java
  • 多态原理探究

    1. 多态的目的

       我们不希望把对象看作是某一个特殊类型的成员,而是希望把它看作一个基本类型的成员。这样就允许我们编写不依赖于特殊类型的代码。

       这样就可以不必修改一般的处理函数,而只需要通过派生新的类型来达到程序拓展的目的。

       要达到这个目的,就需要根据实际的对象类型来判断重写函数的调用。

       a. 如果父类指针指向的是父类对象则调用父类中定义的函数。

       b. 如果父类指针指向的是子类对象则调用子类中定义的重写函数。

     

    2. 如何产生多态?

       使用virtual声明的函数被重写后即可展现多态特性。多态使用的3个条件:

       a. 有继承

       b. 有virtual重写

       c. 有父类指针(引用)指向子类对象。 

    3. C++编译器如何实现多态

       理论知识如下:

       a. 当类中声明虚函数时,编译器会在类中生成一个虚函数表vtable。

       b. 虚函数表是一个存储类成员函数指针的数据结构。

       c. 虚函数表是由编译器自动生成与维护的。

       d. virtual成员函数会被编译器放入虚函数表中。

       e. 当存在虚函数时,每个对象中都有一个指向虚函数表的指针,即vptr指针。C++编译器给父类对象、子类对象提前布局vptr指针。

          发生调用时,存在两种情况:

          1)func不是虚函数:编译器可直接确定被调用的成员函数

          2)func是虚函数:编译器根据对象的vptr指针,所指的虚函数表中查找func函数并调用,这里的查找和调用都在运行时完成(动态绑定)。

    4. 动态绑定过程

       当编译器发现类中有虚函数的时候,编译器会创建一张虚函数表,把虚函数的函数入口地址放到虚函数表中,并且在类中增加一个指针:vptr,

       这个指针是指向对象的虚函数表。在多态调用的时候,根据vptr指针,找到虚函数表来实现动态绑定。

       注:在对象构建的时候,也就是在对象初始化调用构造函数的时候,编译器默认会在编写的每一个构造函数中,增加一些vptr初始化的代码。

           如果没有提供构造函数,编译器会提供默认的构造函数,会在默认构造函数中做这个工作,初始化vptr指针,使它指向本对象的虚函数表。

       子类继承基类的vptr指针,这个指针指向基类虚函数表,当子类调用构造函数时,子类的vpointer指针便会指向子类的虚函数表。

       

       通过虚函数表指针Vptr调用重写函数是在程序运行时进行的,编译器在编译的时候需要额外插入许多查找,判断的代码,运行时执行这些代码

       才能确定真正应该调用的函数。而普通成员函数是在编译时就确定了调用的函数。在效率上,虚函数的效率要低很多。

       出于效率考虑,没有必要将所有成员函数都声明为虚函数。

    5. 构造函数和析构函数能不能是virtual的?

       构造函数不能用virtual修饰:我们知道多态是发生在对象已经建立的情况下,而构造函数调用时对象还没有建立,也就不存在多态。

       析构函数可以用virtual修饰:此时对象已经建立,我们希望在delete p(p为指向子类对象的基类指针)的时候能够调用子类自己的析构函数来释放资源。

     

  • 相关阅读:
    Postgresql
    Partitioning with PostgreSQL v11 (转发)
    Partitioning with PostgreSQL v11 (转发)
    What is Data Partitioning?(转发)(未完待续)
    How to use table partitioning to scale PostgreSQL(转发)
    PostgreSQL 创建分区表(转发)
    json vs jsonb
    性能不佳的多线程应用程序的常见模式(microsoft)
    提高.net程序性能和稳定性-CLR Profile(转发)
    检查c#代码内存泄露工具-CLR Profiler工具使用(转发)
  • 原文地址:https://www.cnblogs.com/yanghh/p/12935373.html
Copyright © 2011-2022 走看看