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;

  }

原文地址:https://www.cnblogs.com/gd-luojialin/p/8252317.html