栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++入门教程 06

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++入门教程 06

学习链接

六、多态性 1. 多态性概述

多态性是面向对象程序设计的重要特性之一,从字面意思上可以简单理解就是:多种形态,多个样子。其实本质意思也是这样,在面向对象程序设计中,指同样的方法被不同对象执行时会有不同的执行效果。

具体来说,多态的实现又可以分为两种:编译时的多态和运行时的多态。前者是编译的时候就确定了具体的操作过程。后者呢是在程序运行过程中才确定的操作过程。这种确定操作过程的就是联编,也称为绑定。

联编在编译和连接时确认的,叫做静态联编 ,前面我们学习的函数重载、函数模板的实例化就属于这一类。

另一种是在运行的时候,才能确认执行哪段代码的,叫做动态联编 ,这种情况是编译的时候,还无法确认具体走哪段代码,而是程序运行起来之后才能确认。

两者相比之下,静态联编由于编译时候就已经确定好怎么执行,因此执行起来效率高;而动态联编想必虽然慢一些,但优点是灵活。

两者各有千秋,有各自不同的使用场景。

下面,围绕静态联编,举个例子:

#include 
using namespace std;
#define PI 3.1415926

class Point
{
private:
    int x,y;

public:
    Point(int x=0,int y=0)
    {
        this->x = x;
        this->y = y;
    }
    double area()
    {
        return 0.0;
    }
};
class Circle:public Point
{
private:
    int r;
public:
    Circle(int x,int y,int R):Point(x,y)
    {
        r = R;
    }
    double area()
    {
        return PI*r*r;
    }
};
  
int main()
{
  
    Point A(10,10);
    cout<area()< 

输出结果:

来分析四个输出:

  • 第一个cout输出A的面积,是Point类中的area方法,面积为0,没有问题。
  • 第二个cout输出B的面积,很明显是派生类Circle的area方法,面积自然按公式计算得出1256.64的值,也没问题。
  • 第三个cout输出的是Point类型指针p指向的Circle类对象的area方法,它输出了0很明显是执行了Point类里的area方法。这里C++实行的是静态联编,即在编译的时候就依据p的类型来定执行哪个area,因此是0
  • 第四种cout也同理,把Circle类型的对象赋给Point类型的引用,C++同样实行静态联编,也输出0

很明显,这不是我们期望的结果,实际上,对于指针、引用,我们更希望执行实际对象的方法,而不是因为这个指针、引用的类型而盲目的确定。这就是如果这么写存在的问题。

如果想达到我们的要求,即无论指针和引用是什么类型,都以实际所指向的对象为依据灵活决定。那么就要更改这种默认的静态联编的方法,采用动态联编,即在运行的时候灵活决定。

来看下一节。

2. 虚函数

虚函数(virtual function),这是一种什么函数呢? 简单讲,就是一个函数前面用virtual声明的函数,一般形式如下:

virtual 函数返回值  函数名(形参){
    函数体
}

虚函数的出现,允许函数在调用时与函数体的联系在运行的时候才建立,即所谓的动态联编。那么在虚函数的派生类的运行时候,就可以在运行的时候根据动态联编实现都是执行一个方法,却出现不同结果的效果,就是所谓的多态。这样解决上一节的问题就有了办法。

接下来,我们只需要把基类中的area方法声明为虚函数,那么主函数中无论Point类型的指针还是引用就都可以大胆调用,无用关心类型问题了。因为他们会依据实际指向的对象类型来决定调用谁的方法,来实现动态联编。

#include 
using namespace std;
#define PI 3.1415926

class Point
{
private:
    int x,y;

public:
    Point(int x=0,int y=0)
    {
        this->x = x;
        this->y = y;
    }
    virtual double area()
    {
        return 0.0;
    }
};
class Circle:public Point
{
private:
    int r;
public:
    Circle(int x,int y,int R):Point(x,y)
    {
        r = R;
    }
    double area()
    {
        return PI*r*r;
    }
};
  
int main()
{
  
    Point A(10,10);
    cout<area()< 

输出结果:

注意:

  1. 虚函数不能是静态成员函数,或友元函数,因为它们不属于某个对象。
  2. 内联函数不能在运行中动态确定其位置,即使虚函数在类的内部定义,编译时,仍将看作非内联
  3. 构造函数不能是虚函数,析构函数可以是虚函数,而且通常声明为虚函数。
3. 虚析构函数

在C++中,不能把构造函数定义为虚构造函数,因为在实例化一个对象时才会调用构造函数,且虚函数的实现,其实本质是通过一个虚函数表指针来调用的,还没有对象更没有内存空间当然无法调用了,故没有实例化一个对象之前的虚构造函数没有意义也不能实现。

但析构函数却是可以为虚函数的,且大多时候都声明为虚析构函数。这样就可以在用基类的指针指向派生类的对象在释放时,可以根据实际所指向的对象类型动态联编调用子类的析构函数,实现正确的对象内存释放。

#include 
using namespace std;
class Point
{
private:
    int x,y;
    int *str;
  
public:
    Point(int x=0,int y=0)
    {
        this->x = x;
        this->y = y;
        str = new int[100];
    }
    ~Point()
    {
        delete []str;
        cout<<"Called Point's Destructor and Deleted str!"< 

输出结果:

可以清楚的看到,仅仅调用了基类的析构函数,这样一来派生类中new出来的4*100字节的内存就会残留,造成内存泄漏!

而如果把基类中析构函数声明为virtual,则结果大有不同!这个时候多态效应出现,会先调用释放派生类的空间,然后再释放基类的内存空间,完美结束:

#include 
using namespace std;
class Point
{
private:
    int x,y;
    int *str;
  
public:
    Point(int x=0,int y=0)
    {
        this->x = x;
        this->y = y;
        str = new int[100];
    }
    virtual ~Point()    // 注意这一行
    {
        delete []str;
        cout<<"Called Point's Destructor and Deleted str!"< 

输出结果:

以上,这就是虚析构函数带来的好处。

4. 纯虚函数与抽象类

纯虚函数,就是没有函数体的虚函数。

就是这样定义的函数:

virtual 返回值  函数名(形参)=0;

可以看到,前面virtual与虚函数定义一样,后面加了一个=0。表示没有函数体,这就是一个纯虚函数。包含纯虚函数的类就是抽象类,一个抽象类至少有一个纯虚函数。

抽象类的存在是为了提供一个高度抽象、对外统一的接口,然后通过多态的特性使用各自的不同方法,是C++面向对象设计以及软件工程的核心思想之一。

抽象类的特点总结如下:

  1. 抽象类无法实例出一个对象来,只能作为基类让派生类完善其中的纯虚函数,然后再实例化使用。
  2. 抽象类的派生来依然可以不完善基类中的纯虚函数,继续作为抽象类被派生。直到给出所有纯虚函数的定义,则成为一个具体类,才可以实例化对象。
  3. 抽象类因为抽象、无法具化,所以不能作为参数类型、返回值、强转类型
  4. 接着第三条,但抽象类可以定义一个指针、引用类型,指向其派生类,来实现多态特性。

虚函数是C++中很重要的一部分内容,一定要深入理解!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/348042.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号