2.4 多态和虚函数

多态和虚函数

  • 多态性:指不同类型的对象接收相同的消息时产生的不同的行为.
    • 消息:主要是指对类的成员函数的调用
    • 不同的行为:指成员函数的不同实现

多态概述

  • C++中,多态性分为两种:编译时的多态性运行时的多态性.
    • 编译时的多态性:通过函数或运算符的重载来实现
    • 运行时的多态性:通过虚函数来实现.它指在程序执行之前,根据函数和参数还无法确定应该调用哪一个函数,必须在程序的执行过程中,根据具体的执行情况动态地确定.
  • 联编(binding,又称绑定):就是将一个标识符和一个存储地址联系在一起的过程,或是一个源程序经过编译,连接,最后生成可执行代码的过程
  • 两种编译方式:静态联编动态联编
    • 静态联编:这种联编在编译阶段完成,由于联编过程在程序运行前完成,所有称为早期联编.
    • 动态联编:指这种联编要在程序运行时动态进行,所以又称晚期联编

虚函数

#include <iostream>
using namespace std;

class CShape
{
public:
    virtual float area()        // 将area定义为虚函数
    {
        return 0.0;
    }
};

class CTriangle : public CShape
{
public:
    CTriangle(float h,float w)
    {
        H = h;
        W = w;
    }
    float area()
    {
        return (float)(H*W*0.5);
    }
private:
    float H,W;
};

class CCircle:public CShape
{
public:
    CCircle(float r)
    {
        R = r;
    }
    float area()
    {
        return (float)(3.14159265*R*R);
    }
private:
    float R;
};

int main()
{
    CShape *s[2];                   // 定义基类CShape的指针
    s[0] = new CTriangle(3,4);      // s[0]指向派生类CTriangle
    cout << s[0]->area() << endl;
    s[1] = new CCircle(5);          // s[1]指向派生类CCircle
    cout << s[1]->area() << endl;

    return 0;
}
/*
* 6
* 78.5398
 */
  • 该例子通过虚函数,达到了用基类指针访问派生类对象成员函数的目的,从而使一个函数具有多种不同版本

  • 注意

    • 虚函数在重新定义时,参数的个数类型都必须和基类中的虚函数完全匹配
    • 只有通过基类指针才能实现虚函数的多态性,若虚函数的调用是通过普通方式来进行的,则不能实现其多态性.

      CShape ss;
      cout << ss.area() << endl;
      // 输出结果为0.0
    • 如果不使用new来创建相应的派生类对象指针,也可通过使用&运算符来获取对象的地址

      void main()
      {
          CShape *p1,*p2;
          CTriangle tri(3,4);
          CCircle cir(5);
          p1 = &tri;
          p2 = &cir;
          cout << p1->area() << endl;
          cout << p2->area() << endl;
      }
    • 虚函数必须是类的一个成员函数,不能是友元函数,也不能是静态的成员函数.

    • 可以把析构函数定义为虚函数,但是不能将构造函数定义为虚函数.通常在释放基类中和派生类中动态申请存储空间时,也要把析构函数定义为虚函数,以便实现撤销对象时的多态性.

纯虚函数和抽象类

  • 在定义一个基类时,若出现:无法定义基类中虚函数的具体实现,其实现完全依赖于其不同的派生类.这时,可将基类中的虚函数声明为纯虚函数
  • 声明纯虚函数的格式:
    virtual <函数类型><函数名>(<形参表>) = 0;
    与一般的虚函数相比,多了个”=0”,把函数赋值为0,本质上是将指向函数的指针的初值赋值为0.注意,纯虚函数不能有具体的实现代码
  • 抽象类:指至少包含一个纯虚函数的特殊的类.它本身不能被实例化,即不能声明一个抽象类的对象.**必须通过继承得到派生类后,在派生类中定义了纯虚函数的具体实现代码,才能获得一个派生类的对象.
#include <iostream>
using namespace std;

class CShape
{
public:
    virtual float area() = 0;       // 将area定义为纯虚函数
};

class CTriangle : public CShape
{
public:
    CTriangle(float h,float w)
    {
        H = h;
        W = w;
    }
    float area()
    {
        return (float)(H*W*0.5);    // 在派生类中定义纯虚函数的具体实现代码
    }
private:
    float H,W;
};

class CCircle:public CShape
{
public:
    CCircle(float r)
    {
        R = r;
    }
    float area()                    // 在派生类中定义纯虚函数的具体实现代码
    {
        return (float)(3.14159265*R*R);
    }
private:
    float R;
};

int main()
{
    CShape *pShape;
    CTriangle tri(3,4);
    cout << tri.area() << endl;
    pShape = &tri;
    cout << pShape->area() << endl;
    CCircle cri(5);
    cout << cri.area() << endl;
    pShape = &cri;
    cout << pShape->area() << endl;

    return 0;
}
/*
 * 6
 * 6
 * 78.5398
 * 78.5398
 */
  • 与虚函数使用方法相同,纯虚函数也可以声明指向抽象类的指针,但是该指针不能指向任何抽象类的对象(因为不存在),但可以通过该指针获得对派生类成员函数的调用.
发布了40 篇原创文章 · 获赞 55 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/A807296772/article/details/77622018
今日推荐