C++继承性和多态性(七)

1.多态性的概念:

  多态性是面向对象程序设计的重要特性。利用多态性可以设计和实现一个易于扩展的系统。

 C++中,多态性是指具有不同功能的函数用同一个函数名,即用同一函数名调用不同内容的函数。

  现实生活中有很多多态性的例子。

  多态性的一般表述:向不同的对象发送同一消息(调用函数),不同的对象会产生不同的行为(方法)。

  例如,运算符+调用operator+函数,对不同类型数据的操作互不相同。

    从系统实现的角度看,多态性分为两类:

    ①静态多态性:系统在编译的时候就能知道要调用的是哪个函数。也叫做编译时的多态性。(如函数重载)

     ②动态多态性:程序在运行过程中才动态地确定操作所针对的对象。又叫做运行时的多态性

2.静态联编和动态联编:

静态联编: 

        对程序中出现的标识符进行的绑定和解析过程,在产生目标代码的编译时固定下来

 

       静态联编又称为静态绑定和早期绑定。


#include

using namespace std;

class Point

{private:

      double x, y;

  public:

       Point(double i, double j)

  {

  x=i; 

  y=j;

  }

       double Area()  const 

  {  

  return 0.0;

  }

};


class Rectangle:public Point

{ public:

      Rectangle(double i, double j, double k, double l);

      double Area() const  

 {

 return  w*h;

 }

  private:

      double w,h;

};


Rectangle::Rectangle(double i, double j, double k, double l) :Point(i,j) 

w=k;  

h=l; 

}


void fun(Point &s)  //一般函数,参数是基类引用

cout<<"Area="<<s.Area()<<endl;  

}



int main()

{

    Rectangle rec(3.0, 5.2, 15.0, 25.0);

    fun(rec);

    return 0;

 

}

什么是动态联编: 

        根据目标对象的动态类型(而不是静态类型),在程序运行时(而不是在编译时)将函数名绑定到具体的函数实现上。

       动态联编又称为动态绑定晚期绑定

动态联编的实现——虚函数 

 

       C++提供了virtual关键字用于指定函数是否为虚函数。如果在一个函数声明前面加上virtual,则这个函数为虚函数,系统将对其进行动态联编

动态联编的实现过程:

 

   在程序编译时:

    ①为每一个有虚函数的类设置一个虚函数表v_table,一个指针数组,存放每个虚函数的入口地址。

    ②在函数调用处插入一个隐藏的,指向虚函数表的指针v_pointer;

   在程序运行中:

 

       根据对象的v_pointer,在相应的虚函数表中获得函数入口,来调用正确的函数。

3.虚函数的定义与使用:

  虚函数的定义方法:

  ① 在基类中以关键字virtual说明;

     virtual <</span>函数返回类型> <</span>函数名>(<</span>参数表>)

   : virtual double Area( );

  在派生类中重新定义一个同名非静态成员函数。

  3点说明:

A.派生类中同名函数必须与基类虚函数完全一致(即函数名、参数个数与类型、返回类型都相同)。
B.采用基类对象指针或引用来调用虚函数。

 

C.派生类必须以公用方式继承

只有满足上面3点,程序才会按动态联编的方式调用函数,否则虚函数将按静态联编的方式调用。

#include< iostream >

using namespace std;

class Point

{ private:

      double x, y;

   public:

       Point(double i, double j) {x=i; y=j;}

       virtual double Area()  const

       { return 0.0;}

 

};

class Rectangle:public Point

{ public:

      Rectangle(double i, double j, double k, double l);

      virtual double Area() const  {return  w*h;}

  private:

      double w,h;

};

 

 

Rectangle::Rectangle(double i, double j, double k, double l) :Point(i, j) { w=k; h=l; }

void fun(Point &s)  //一般函数,参数是基类引用

 

{ cout<<"Area="<<s. Area()<<endl }

int main()

{

    Rectangle rec(3.0, 5.2, 15.0, 25.0);

    fun(rec);

    return 0;

 

}

运行结果:

 

     Area=375

总结虚函数的使用方法:

  在基类用virtual声明成员函数为虚函数;

  在派生类中重新定义此函数;

      C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。

  定义一个指向基类的指针(或引用);

 

  通过重新对该指针(或引用)做同类族对象赋值,调用该类对象同名虚函数。

虚函数与指向基类的指针(引用)变量配合使用,就能方便地调用同一类族中不同类对象的同名函数。从而实现运行时的多态性。

在什么情况下应该声明虚函数:

    函数所在的类会作为基类,并且有更改功能的需要;

    对于继承后不需要更改功能的函数不要声明为虚函数;

    考虑对成员函数的调用是否通过指针或引用;

  虚函数的意义:

    如果说:数据封装使得代码模块化 继承实现了代码重用

 

    那么,虚函数采用动态联编技术造就了程序设计的多态性——接口重用

虚析构函数:

      如果基类的析构函数为虚析构函数,派生类的析构函数也均为虚析构函数。

  如果基类的析构函数为虚析构函数,无论基类指针指的是哪一个派生类对象,当该对象撤销时,系统都会采用动态联编,调用相应的析构函数。

 

  程序中最好把析构函数声明为虚函数!即使基类不需要析构函数,也显式地定义一个函数体为空的虚析构函数。

 

 

  构造函数不能声明为虚函数!!!

4. 纯虚函数和抽象类:

  对于物理上无法实现逻辑上又不得不存在的抽象的虚函数,可以将其在基类中用不包括任何代码纯虚函数来定义。

  纯虚函数的定义方法:

 

  virtual 函数返回类型 > < 函数名 >( 参数表 )0

---------------------------------------------------

virtualchar *Type() const { return NULL; }        //虚函数

virtualdouble Volume() const { return 0;}         //虚函数

 

virtualdouble SurfaceArea() const { return 0; }  //虚函数

---------------------------------------------------

  virtual char *Type() const = 0               //纯虚函数

  virtual double Volume() const = 0          //纯虚函数

 

  virtual double SurfaceArea() const = 0    //纯虚函数

---------------------------------------------------

  抽象类:

  包含一个或多个纯虚函数的类叫做抽象类。

  有关抽象类:

    不能创建抽象类的对象;

  抽象类不能作为参数类型、函数返回和显式转换;

  可以定义指向抽象类的指针;

   不能调用抽象类的纯虚函数,它仅仅是为派生类提供的一个公共接口; 

       C++采用抽象类,将接口和实现分离开来。

 

posted @ 2014-05-19 22:30  dreamsyeah  阅读(290)  评论(0编辑  收藏  举报