zoukankan      html  css  js  c++  java
  • 多态与虚函数

    多态是指同一名字的事物可以完成不同的功能。多态可以分为编译时的多态和运行时
      的多态。前者主要是指函数重载、对重载函数的调用,在编译时就能根据实参确定应
      该调用哪个函数。后者则和继承、虚函数等概念相关。
     
         通过基类指针实现多态:
          派生类对象的地址可以赋值给基类指针。对于通过基类指针调用基类和派生类中
       都有的同名、同参数表的虚函数语句,编译时并不确定要执行的是基类还是派生
       类的虚函数,而当程序运行到该语句时,如果基类指针指向一个基类对象,则基
       类的虚函数被调用,如果基类的指针指向一个派生类对象,则派生类虚函数被调
       用。这种机制就叫做多态。
      
      通过基类引用实现多态:
             通过基类的引用调用虚函数的语句也是多态的。
      
     虚函数:
         在函数声明前加上virtual关键字的成员函数。virtual关键字只在类定义中的成员函
      数声明处使用,不能再类外部写成员函数体时使用。
      
      静态成员函数不能是虚函数。
      包含虚函数的类称为多态类。
      
     多态的作用:
         在面向对象的程序设计中,使用多态能够增加程序的可扩充性,即程序需要修改或增加功能
      时,只需改动或增加较少的代码。此外,使用多态也能够起到精简代码的作用。

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    class fruit{
        private:
            double price;
        public:
            virtual void Print(){
                cout << "Base Class" << endl;
            }
    }; 
    
    class apple:public fruit{
        private:
            string area;
        public:
            virtual void Print(){
                cout << "Derived Class" << endl;
            } 
    };
    
    int main()
    {
        fruit f;
        apple a;
        fruit *pf1 = &f;
        fruit *pf2 = &a;
        fruit &pf3 = a; 
        pf1->Print();
        pf2->Print();
        pf3.Print(); 
        
        return 0;
    }
    
    /*
        输出结果:
            Base Class
            Derived Class
            Derived Class 
    */ 

    关于多态的主意事项:
         类的成员函数之间而已互相调用。在成员函数(静态成员函数、构造函数和析构函数除外)中
      调用其它虚成员函数的语句时多态的。

    #include <iostream>
    
    using namespace std;
    
    class fruit{
        public:
            void fun(){
                Print();
            } 
            virtual void Print(){
                cout << "Base Class" << endl;
            }
    }; 
    
    class apple:public fruit{
        public:
            virtual void Print(){
                cout << "Derived Class" << endl;
            } 
    };
    
    int main()
    {
        apple a;
        a.fun();   // 输出:Derived Class 
        // 由于a是一个apple类对象,所以调用的是apple中的Print函数 
        
        return 0;
    }

    在构造函数和析构函数中调用虚函数:
         在构造函数和析构函数中调用虚函数不是多态,因为编译时即可确定调用的是哪个函
      数。如果本类中有该函数,调用的就是本类中的函数;如果本类中没有,调用的就是
      直接基类的函数;如果直接基类中没有,就调用间接基类中的,以此类推。
     
     注意区分多态和非多态的情况:
         要注意,通过基类指针或引用调用成员函数的语句,只有当该成员函数时虚函数时才
      会是多态。如果该成员函数不是虚函数,那么这条函数调用语句就是静态联编的,编
      译时就能确定调用的时哪个类的成员函数。
      
     C++规定,只要基类中某个函数被声明为虚函数,则派生类中的同名、同参数表的成员函数
     即使前面不加virtual关键字,也自动成为虚函数。

    虚析构函数:
           有时我们会将基类指针指向一个用new运算符动态生成的派生类对象,在释放该对象时是
        通过释放指向它的指针实现的。这时,由于delete语句时静态编联的,编译器在此处无
        法此时这个指针是指向哪个对象的,只会根据指针是基类类型,而调用基类的析构函数,
        从而造成程序的问题。这时,我们可以通过将基类的析构函数声明为虚函数来解决这个
        问题。

    #include <iostream>
    
    using namespace std;
    
    class fruit1{
        public:
            ~fruit1(){
                cout << "Base Class" << endl;
            }
    }; 
    
    class apple1:public fruit1{
        public:
            ~apple1(){
                cout << "Derived Class" << endl;
            } 
    };
    
    class fruit2{
        public:
            virtual ~fruit2(){
                cout << "Base Class" << endl;
            }
    }; 
    
    class apple2:public fruit2{
        public:
            virtual ~apple2(){
                cout << "Derived Class" << endl;
            } 
    };
    
    int main()
    {
        fruit1 *pf = new apple1;
        delete pf;    
        fruit2 *p_f = new apple2;
        delete p_f; 
        
        return 0;
    }
    
    /*
        输出结果:
            Base Class
            Derived Class
            Base Class 
    */ 

     纯虚函数和抽象类:
         纯虚函数就是没有函数体的虚函数。包含纯虚函数的类就叫做抽象类。
      纯虚函数的写法就是在函数声明后加"=0"
      
     抽象类不能独立生成对象。
     
     抽象类的作用:
         抽象类可以作为基类,用来派生新类。可以定义抽象类的指针或引用,并让它们指向或引
      用抽象类的派生类的对象,为多态的实现提供条件。独立的抽象类的对象不存在,但是包
      含在派生类对象中的抽象类的对象是可以存在的。
      
     如果一个类从抽象类派生而来,当且仅当它对基类中的所有纯虚函数都进行覆盖并都写出函数
     体,它才能成为非抽象类。

    class fruit1{                     // 抽象类 
        public:
            virtual void Print() =0;  // 纯虚函数 
    }; 
  • 相关阅读:
    说一下Mysql索引
    B树、B-树、B+树、B*树之间的关系
    Mybatis Plus 的优点
    JVM垃圾回收机制
    Java中的集合
    MQ 面试题
    Redis 双写一致性
    Redis 主从复制
    C#中Abstract和Virtual的区别
    C#设计模式(2)——简单工厂模式
  • 原文地址:https://www.cnblogs.com/lnlin/p/7637878.html
Copyright © 2011-2022 走看看