zoukankan      html  css  js  c++  java
  • c++中的虚函数

       多态是指使用相同的函数名来访问函数不同的实现方法,即“一种接口,多种方法”,用相同的形式访问一组通用的运算,每个运算可能对应的行为不同。


       C++支持编译时多态和运行时多态,运算符重载和函数重载就是编译时多态,而派生类和虚函数实现运行时多态。

       1、运行时多态:

    class A
     {
      public:
         virtual  void play() 
         {
          cout<< "A:play"<<endl;
         }
      };
    
    class B : public  A
     {
      public:
        void play()
         {
          cout<<"B: play"<<endl;
        }    
    };
    
    int main()
    {
    	A class_A;
    	B class_B;
    	A* p;
    	p = &class_A;
    	p -> play();
    	p = &class_B;//父类指针指向子类对象
    	p -> play();
    
    	return 0;
    }
     
    

      输出结果:

           A:play

           B:play

          虚函数实现多态,具体到这个例子,可以得出,多态性体现在父类指针可以指向子类对象,并且可以访问子类的成员函数。假设基类的成员函数不是虚函数,则输出结果是:

           A:play

           A:play 

    2、纯虚函数      

    纯虚函数的定义形式为 virtual void play() = 0;含有纯虚函数的类是不能实例化的,纯虚函数相当于接口,需要在派生类中实现函数;含有纯虚函数的类被叫做抽象类;在项目中纯虚函数的实践:

       

      class Base
      {
         public:
          virtual void play() = 0;
        };
    class Base_Test : public Base {
    public: void play()    { cout<<"Base_Test:play"<<endl;
       }
    };

      

    3、虚基类

          虚基类的引出主要是为了解决继承中的二义性问题,在多个派生类中,定义了同名函数,这时再在main函数里面通过基类调用该方法时,编译器就犯难了。因为它不知道你到底是想用哪一个派生类里面的方法。通过下面的例子来详细阐述:

          大家都知道C++是支持多重继承的,那么就会遇到这样一个问题。如果一个派生类的多个基类是从一个共同的基类派生出来的,那么这个派生类会出现多个最底层基类的拷贝,程序中如何分辨呢。虚基类是让基类只有一个拷贝,程序中就不会出现不确定性。虚基类在派生类中声明:格式如下:class 派生类名:virtual 继承方式 基类。

    #include <iostream>
    using namespace std;
    class Base
    {
    public :
      Base()
      {
       cout<<"Base()"<<endl;
      }
    ~Base() { cout<<"~Base()"<<endl; } }; class Continuator1 : public Base { public: Continuator1() { cout<<"Continuator1()"<<endl; } ~Continuator1() { cout<<"~Continuator1()"<<endl; } }; class Continuator2 : public Base { public: Continuator2() { cout<<"Continuator2"<<endl; } ~Continuator2() { cout<<"~Continuator2()"<<endl; } }; class Continuator : public Continuator1,public Continuator2 { public: Continuator() { cout<<"Continuator()"<<endl; } ~Continuator() { cout<<"~Continuator()"<<endl; } private: Base base; }; int main() { Continuator c; return 0; }

      

    这个例子的运行结果是:

          从构造函数调用的顺序可以看出,在声明Continuator 对象时。首先调用基类Continuator1的构造,调用Continuator1的构造时就要先调用Base的构造函数,然后再调用Continuator1的构造函数,然后调用Continuator2,再调用成员对象的构造函数初始化成员对象base;最后调用派生类Continuator1的构造函数。析构函数调用顺序和构造函数调用顺序相反。

          把Continuator1和Continuator2类的定义修改为:

    class Continuator1 :virtual public Base
    {
    public:
    Continuator1()
    {
    cout<<"Continuator1()"<<endl;
    }
    ~Continuator1()
    {
    cout<<"~Continuator1()"<<endl;
    }
    };
    
    class Continuator2 :virtual public Base
    {
    public:
    Continuator2()
    {
    cout<<"Continuator2"<<endl;
    }
    ~Continuator2()
    {
    cout<<"~Continuator2()"<<endl;
    }
    };
    

      

    输出为:

      

    由此可以看出虚基类的用法;

  • 相关阅读:
    过滤器
    HTTP会话的使用和管理
    Servlet技术(下)
    Servlet技术(上)
    Web运作原理
    Tomcat简介
    Java Web应用
    java io
    【node.js】node.js安装yarn报错:Could not create the Java Virtual Machine
    【微信小程序】微信小程序页面url传参,使用JSON.parse报错Unexpected end of JSON input
  • 原文地址:https://www.cnblogs.com/nobbyoucanyouup/p/4593881.html
Copyright © 2011-2022 走看看