zoukankan      html  css  js  c++  java
  • 16多态

    多态性:在程序多次执行时,某一确定位置的函数调用执行了不同的函数体。

    虚函数

    虚函数的定义

    1.在成员函数(非静态、非构造函数)原型前加上关键字virtual

    2.类的虚函数通过继承向下传递,在派生类中既可以直接继承也可以重定义,重定义时函数原型前可以省略virtual,也可以改变访问模式(不提倡),但必须和原来的虚函数具有相同的返回值类型和参数表

    虚函数的调用

    用对象指针或对象引用对虚函数的调用、成员函数(构造函数和析构函数除外)的函数体中对虚函数的调用将实行动态绑定,其它对虚函数的调用(如对象名加成员选择运算符、虚函数的调用前加类名和作用域运算符)实行静态绑定

    示例

    #include <iostream.h>

     class A

      {public:

        virtual void f( )

         {cout<<"A::f( ) called"<<endl;}

      };

     class B:public A

      {public:

        B( ){f( );} //静态绑定

        void g( ){f( ); //动态绑定

                  A::f( ); //静态绑定                                      

                 }

      };

    class C:public B

      {public:

        void f( )

         {cout<<"C::f( ) called"<<endl;}

      };

     main( )

     {C c;

      c.g( );

      return 0;

     }

    抽象基类和纯虚函数

    实现多态性的前提:

    1.需要有共同的基类

    2.需要在基类中定义共同的接口

    3.接口要定义为虚函数

    如果基类的接口没办法实现怎么办?

    解决方法:

    1.不实现这些接口:纯虚函数

    2.包含纯虚函数的类:抽象基类

    纯虚函数

    1.没有函数体的“初始化为0”的函数

     //纯虚函数

     virtual double area() const = 0;   

    2.纯虚函数不需要实现,不能被执行

    3.通过定义、重定义或继承获得

    抽象类和具体类

    1.包含纯虚函数(且未对其重定义)的类不能实例化对象,是抽象类

    2.如果一个类不是抽象类,则是具体类。

    3.抽象类存在的意义是作为其它类的基类,也叫抽象基类

    定义或继承获得纯虚函数示例

    #include <iostream.h>

     class A

      {public:

        virtual void f( )=0; //纯虚函数定义

      };

     class B:public A

      {public:

        B( ){f( );} //静态绑定,错

        void g( ){f( ); //动态绑定

                  A::f( ); //静态绑定,错

                 }

      }; // 类B继承了类A的纯虚函数f,且没有重定义

    class C:public B

      {public:

        void f( )

         {cout<<"C::f( ) called"<<endl;}

      };

     // 类C继承了类A的纯虚函数f,但对f作了重定义

     main( )

     {C c;

      c.g( );

      return 0;

     }

    通过重定义获得纯虚函数示例

    #include <iostream.h>

     class A

      {public:

        virtual void f( )

         {cout<<"A::f( ) called"<<endl;}

      };

     class B:public A

      {public:

        virtual void f( )=0;

       //把虚函数f重定义为纯虚函数,virtual可省略

        void g( ){f( );}

      };

    class C:public B

      {public:

        void f( )

         {cout<<"C::f( ) called"<<endl;}

      };

     // 类C继承了类A的虚函数f和类B的纯虚函数f,

     // 但对f作了重定义

     main( )

     {C c;

      c.g( );

      return 0;

     }

    虚析构函数

    1.构造函数的执行顺序:从上到下

    2.析构函数的执行顺序:从下到上

    3.创建对象时要执行正确的构造函数

    4.撤销对象时要执行正确的析构函数

    动态对象的创建

      new ClassName(…);

    ClassName指明了要调用的构造函数

    动态对象的撤销

     delete 基类指针;

    如果基类指针指向的是派生类的对象呢?

    解决方案:把析构函数定义为虚函数

      对于  delete 基类指针;   //该类的析构函数为虚函数

    程序会根据基类指针指向的对象的类型确定要调用的析构函数

    基类的析构函数为虚函数,所有派生类的析构函数都是虚函数

    例子一:虚函数与多态性

    //文件base.h,定义基类

     #if !defined __BASE__H__

     #define __BASE__H__

     #include <iostream.h> 

     class Base

     {public:

       virtual void show( )

        {cout<<"I am Base's object! ";

        }

     }; 

     #endif

    //文件derived.h,定义类Derived

     #if !defined __DERIVED__H__

     #define __DERIVED__H__

     #include "base.h" 

     class Derived :public Base

     {public:

       void show()

        {cout<<"I am Derived's object! ";

        }

     }; 

     #endif

    //文件main.cpp,函数调用的动态绑定

     #include "derived.h"

     main()

     {Base *bPtr, bObj;

      Derived dObj;

      bPtr= &bObj; //基类指针指向基类对象

      bPtr->show(); //用指针调用虚函数,动态绑定

      bPtr= &dObj; //基类指针指向派生类对象

      bPtr->show(); //用指针调用虚函数,动态绑定

      return 0;

     } 

    或者

    //修改文件main.cpp,用对象引用调用虚函数

     #include "derived.h"

     main()

     {Derived dObj;

      Base bObj, &cObj = dObj;

      bObj.show(); //用对象调用虚函数,静态绑定

      cObj.show();//用对象引用调用虚函数,动态绑定

      return 0;

     }

    例子二:多态性的应用实例

    #include <iostream.h>

     class shape

     {public:

       virtual double area(){return 0.0; }

       virtual ~shape(){ }

     };

     double total(shape *s[],int n)

     {double sum=0;

      for(int i=0;i<n;i++)

       sum+=s[i]->area(); //动态绑定

      return sum;

     }

    class triangle: public shape

     {protected:

       double  H,W;

      public:

       triangle(double h, double w){H=h;W=w;}

       double area(){return H*W*0.5;}

     };

     class rectangle: public triangle

     {public:

       rectangle(double h, double w)

        :triangle(h,w){ }

       virtual double area();

     };

     double rectangle::area(){return H*W;}

    class screen

     {private:

       shape *s[100];

       int n;

      public:

       screen(){n=0;}

       void addshapetoscreen(shape *sp)

        {if(n<100)n++;

         s[n-1]=sp;

        }

       double total()

        {double sum=0;

         for(int i=0;i<n;i++)

          sum+=s[i]->area();

         return sum;

        }

     };

    main()

     {shape *s[100];

      s[0]=new triangle(2.2,3.3);

      s[1]=new rectangle(2.0,4.0);

      cout<< total(s,2) << endl;

      screen ss;

      ss.addshapetoscreen(s[0]);

      ss.addshapetoscreen(s[1]);

      cout<<ss.total();

      for (int i=0;i<2;i++)

       delete s[i];

      return 0;

     }

    //增加新的图形不需要修改total函数和screen类

    //增加相关图形类

     class circle: public shape

     {private:

       double radius;

      public:

       circle(double r)

        {radius=r;}

       double area()

        {return radius*radius*3.14159;}

     };

     //修改主函数

     main()

     {shape *s[4];

      s[0]=new triangle(2.2,3.3);

      s[1]=new rectangle(2.0,4.0);

      s[2]=new circle(5.0);

      s[3]=new circle(8.0);

      cout<< total(s,4) <<endl;

      screen ss;

      ss.addshapetoscreen(s[0]);

      ss.addshapetoscreen(s[3]);

      cout<<ss.total();

      for (int i=0;i<4;i++)

       delete s[i];

      return 0;

     }

    例子三:抽象基类的例子

    //文件shape.h,定义抽象基类Shape

     #if !defined __SHAPE__H__

     #define __SHAPE__H__

     #include <iostream.h>

     class Shape

     {public:

       virtual double area() const = 0;

       virtual void show() const = 0;

     }; 

     #endif

    //文件circle.h,定义派生类Circle

     #if !defined __CIRCLE__H__

     #define __CIRCLE__H__

     #include "shape.h"

     #define PI 3.1416

     class Circle :public Shape

     {public:

       Circle(double = 0.0,

              double = 0.0, double = 1.0);

       double area() const;

       void show() const;

      private:

       double x,y;

       double r;

     };

     #endif

    //文件circle.cpp,实现类Circle

     #include "circle.h"

     Circle::Circle(double a,

                    double b, double c)

     { x = a;

       y = b;

       r = c;

     }

     double Circle::area() const

     {return PI*r*r; 

     } 

     void Circle::show() const

     {cout<<"I am a Circle: ";

     }

     // Circle是具体类

    //文件rectangle.h,定义派生类Rectangle

     #if !defined __RECTANGLE__H__

     #define __RECTANGLE__H__

     #include "shape.h"

     class Rectangle :public Shape

     {public:

       Rectangle(double = 1.0, double = 1.0);

       double area() const;

       void show() const;

      private:

       double length;

       double width;

     };

     #endif

    //文件rectangle.cpp,实现类Rectangle

     #include "rectangle.h"

     Rectangle::Rectangle(double a, double b)

     { length = a;

       width = b;

     }

     double Rectangle::area() const

     {

      return length*width;

     }

     void Rectangle::show() const

     {

       cout<<" I am a Rectangle: ";

     } // Rectangle是具体类

    //文件main.cpp,测试类Shape的虚函数

     #include "circle.h"

     #include "rectangle.h"

     void callArea(Shape &obj)

     {obj.show(); //动态绑定

      cout<<"area = "<<obj.area()<<endl;

     } // obj.area()动态绑定

     main()

     {Circle cir(0.0, 0.0, 2.5);

      Rectangle rec(2.4, 5.3);

      //能用Shape类声明对象吗?

      callArea(cir);

      callArea(rec);

      return 0;

     }

    例子四:虚析构函数的例子

    //文件employee.h,定义基类Employee

     #include <iostream.h>

     #if !defined __EMPLOYEE__H__

     #define __EMPLOYEE__H__

     class Employee

     {public:

       Employee()

       {cout<<"Employee begin!"<<endl;

       }

       virtual ~Employee()

       {cout<<"Employee end!"<<endl;

       }

     };

     #endif

    //文件programmer.h,定义派生类Programmer

     #include <iostream.h>

     #include <string.h>

     #include "employee.h"

     class Programmer: public Employee

     {public:

       Programmer(char *str)

       {cout<<"Programmer begin!"<<endl;

        name = new char[strlen(str)+1];

        strcpy(name, str);

       }

       ~Programmer()

       {delete [] name;

        cout<<"Programmer end!"<<endl;

       }

      private:

       char *name;

     };

    //文件accountant.h,定义派生类Accountant

     #include <iostream.h>

     #include "employee.h"

     class Accountant: public Employee

     {public:

       Accountant(int n)

       {cout<<"Accountant begin!"<<endl;

        age = n;

       }

       ~Accountant()

       {cout<<"Accountant end!"<<endl;

       }

      private:

       int age;

     };

    //文件main.cpp

     #include "accountant.h"

     #include "programmer.h"

     const int MAX = 100;

     main()

     { int no;

       //声明储存雇员信息的数组

       Employee *ptr[MAX], *tptr;

       int ENum = 0;

       char name[100];

       int age;

       for (int i=0; i<MAX; i++)

        ptr[i] = NULL;

       //输入雇员信息

       cout<<"Input employees' info:"<<endl;

       cout<<"1 --- Programmer"<<endl

           <<"2 --- Accountant"<<endl

           <<"0 --- exit"<<endl;

       cin>>no;

       while (no)

       {switch (no)

        {case 1:

          cout<<"Please input name:";

          cin>>name;

                //创建程序员对象

          tptr = new Programmer(name);

          ptr[ENum++] = tptr;

          break;

        case 2:

         cout<<"Please input his or her age:";

         cin>>age;

         //创建会计对象

         tptr = new Accountant(age);

         ptr[ENum++] = tptr;

         break;

       default:

         break;

      }

      cout<<"Input another employee's info:“

          <<endl;

      cout<<"1 --- Programmer"<<endl

          <<"2 ---Accountant"<<endl

          <<"0 --- exit"<<endl;

      cin>>no; }

       //撤销所有雇员对象

       for (i=0; i<ENum; i++)

       {

         delete ptr[i];

       }

       return 0;

      }

  • 相关阅读:
    关于词向量工作原理的理解
    LDA-线性判别分析(四)其他几个相关问题
    LDA-线性判别分析(三)推广到 Multi-classes 情形
    LDA-线性判别分析(一)预备知识
    LDA-线性判别分析(二)Two-classes 情形的数学推导
    为什么国内的网盘公司都在 TB 的级别上竞争,成本会不会太高?
    为什么我们喜欢用 sigmoid 这类 S 型非线性变换?
    UFLDL 教程学习笔记(四)主成分分析
    关于协方差矩阵的理解
    UFLDL 教程学习笔记(三)自编码与稀疏性
  • 原文地址:https://www.cnblogs.com/gd-luojialin/p/8252317.html
Copyright © 2011-2022 走看看