多态性与虚函数

35 篇文章 2 订阅
一、什么是多态
  C++有三大特性,封装、继承、多态。多态是面向对象程序设计的一个重要特征。利用多态性可以设计和实现一个易于扩展的系统。多态就是一个事物有多重状态,在C++程序设计中,多态性是指具有不同功能的函数可以用一个函数名,这样就可以用同一个函数名实现不同的功能。
  从系统的角度看,多态分为静态多态和动态多态。静态多态是利用重载实现的,在程序编译时确定要调用的是哪个函数,因此静态多态又称为编译时多态。动态多态是利用虚函数实现的,在程序执行期间才动态的确定操作所针对的对象,因此动态多态又称为运行时多态。
  动态多态和虚函数主要研究的是:当一个基类被继承为不同的派生类时,各派生类可以使用与基类成员相同的成员名,如果在运行时用同一个成员名调用类对象的成员,那么会调用哪一个对象的成员?也就是,通过继承而产生了相关的不同派生类,与基类成员同名的成员在不同的派生类中有不同的含义。即“一个接口,多个方法”。

二、虚函数
1、虚函数的作用
  我们知道在同一个类中是不能定义两个名字相同、参数个数和类型完全相同的函数,否则就是重复定义。但是在类的继承层次结构中,在不同的层次中可以出现名字相同、参数个数和类型相同而功能不同的函数(这是因为类域的原因,即他们在不同的作用域内)。这时系统会根据同名覆盖的原则决定调用的对象。
例:
class Student
{
public:
      void display()
      {
          cout << _age << endl;
      }
protected:
      int _age;
};

class Student1 :public Student
{
public:
     void display()
     {
         cout << _name << "--" << _age << endl;
     }
protected:
      char _name;
};



如果在main函数中有如下定义:
   Student1 s1;
   s1.display();
则这时调用的就是Student1中的display函数。如果要通过s1调用student中的display函数的话,则必须加上基类名限制作用域,如:s1.Student::display();

    Student p;
    p=s1;
    p.display();
这时p调用的是基类的display函数。
   那么有没有一种方法,用同一种调用形式,既能调用派生类又能调用基类的同名函数?即不通过不同的对象名去调用不同派生层次中的同名函数,而是通过指针调用它们。
   例如:用p->display();可以调用不同派生层次中的display函数,只需要在调用之前给指针变量p赋不同的值,使之指向不同的类对象即可。
   C++中的虚函数就是用来解决这个问题的。虚函数的作用是允许在派生类中重新定义与基类同名的函数,并可以通过基类指针或引用来访问基类和派生类中同名函数。

2、如何声明虚函数
  对上面的程序做一点修改,在Student类中声明display函数时,在最左端加一个关键字virtual,即:virtual void display(); 这样就将Student中的display函数声明为虚函数。
如果在main函数中有如下语句:
    Student s;              //基类的对象
    Student1 s1;            //派生类的对象
    Student *p;             //指向基类的指针
    p=&s;                   //让p指向基类对象
    p->display();           //调用的是基类的display函数
    p=&s1;                  //让p指向派生类对象
    p->display();           //调用的是派生类的display函数
  现在用一个指针变量p(指向基类对象的指针变量),就可以调用同一类族中的不同类的虚函数。本类,基类的指针是用来指向基类对象的,如果用它来指向派生类的对象,则进行指针类型的转化,即基类指针指向的是派生类中从基类中继承的部分。在程序修改之前,是无法通过指向基类的指针调用派生类中的函数的。但是声明为虚函数之后,在派生类中的虚函数取代了基类原来的虚函数,因此在使用基类指针指向派生类对象后,调用虚函数就是调用了派生类的虚函数。
  当把基类的某个成员函数声明为虚函数之后,允许在派生类中对该函数重新定义,赋予它新的功能,并可以通过指向基类的指针指向同一类族中不同类的对象,对同一函数调用做出不同的响应。

三、虚函数的使用方法
1、在基类中用virtual声明成员函数是虚函数。(在类外定义时不需要再加virtual)

2、在派生类中重新定义虚函数,要求函数名,函数类型,参数个数和类型完全与基类中的虚函数相同,根据自己的需求定义函数体。C++中规定,当一个成员函数被声明为虚函数后,在派生类中的同名函数都是虚函数。如果在派生类中没有对虚函数重新定义,则派生类简单的继承基类的虚函数。

3、定义一个指向基类对象的指针变量,并使他指向同一类族中需要调用该函数的对象。通过该指针变量调用此虚函数,就相当于指针变量所指向的对象的同名函数。

4、函数重载处理的是同一层次上的同名函数问题,因此是横向重载。虚函数处理的是类的派生层次上的同名函数问题,属于纵向重载。与重载不同的是,虚函数要求函数的首部完全相同。

5、函数重载和通过对象名调用的虚函数,在编译期间即可确定调用的虚函数属于哪一个类,其过程称为静态关联。在运行阶段,基类变量先指向某一个类对象,然后通过此指针变量调用该对象中的函数,这种过程称为动态关联。

四、什么时候使用虚函数
1、因为虚函数是用于类的继承层次结构中的,所以只能将类的成员函数声明为虚函数,而不能将普通函数声明为虚函数。
2、一个成员函数被声明为虚函数后,就不能再同一类族中再定义一个非virtual的但是与虚函数首部相同的函数了。
3、如果一个类作为基类,它的成员函数可能会在派生类中发生改变,则应声明为虚函数。
4、如果是通过指向基类对象的指针调用派生类中成员函数,则应声明为虚函数。

5、使用虚函数,系统会有一定的空间开销。当一个类中有虚函数时,编译系统会为该类构造一个虚函数表,它是一个指针数组,用来存放每个虚函数的入口地址。但是系统在进行动态关联时的时间开销很少,所以多态很高效。

6、一般将析构函数声明为虚析构函数,即时基类不需要析构函数,也要显示的定义一个函数体为空放入虚析构函数,以保证在撤销对象动态分配空间时能得到正确的处理。

五、纯虚函数和抽象类
1、什么是纯虚函数
  有时在类中将某一成员声明为虚函数,并不是因为基类本身的要求,而是因为派生类的需求,在基类中预留一个函数名,具体功能留给派生类区定义。这种情况下就可以将这个纯虚函数声明为纯虚函数。其一般形式是:
       virtual 函数类型 函数名 (参数列表) =0;
注意:
  纯虚函数没有函数体。最后的“=0”只是一种形式,告诉编译系统,它是一个纯虚函数,留在派生类中定义,并没有实际意义。纯虚函数只有在派生类中定义了之后才能被调用。 如果在一个类中声明了纯虚函数,而在派生类中没有对该函数定义,则该虚函数在派生类中仍然为纯虚函数。

2、抽象类
  含有纯虚函数的类就成为抽象类。抽象类只是一种基本的数据类型,用户需要在这个基础上根据自己的需要定义处各种功能的派生类。抽象类的作用就是为一个类族提供一个公共接口。抽象类不能定义对象,但是可以定义指向抽象类的指针变量,通过这个指针变量可以实现多态。
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值