从零开始学C++之虚函数与多态(二):纯虚函数、抽象类、虚析构函数

一、纯虚函数

虚函数是实现多态性的前提

需要在基类中定义共同的接口 接口要定义为虚函数

如果基类的接口没办法实现怎么办?

如形状类Shape

解决方法

将这些接口定义为纯虚函数

在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 定义纯虚函数: class 类名{         virtual 返回值类型 函数名(参数表) = 0;     }; 纯虚函数不需要实现

二、抽象类

作用

抽象类为抽象和设计的目的而声明,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。 对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。

注意

抽象类只能作为基类来使用。 不能声明抽象类的对象。 构造函数不能是虚函数,析构函数可以是虚函数

1、抽象类不能用于直接创建对象实例,可以声明抽象类的指针和引用 2、可使用指向抽象类的指针支持运行时多态性 3、派生类中必须实现基类中的纯虚函数,否则它仍将被看作一个抽象类

#include <iostream>
#include <vector>
#include <string>
using namespace std;

class Shape
{
public:
    virtual void Draw() = 0;
    virtual ~Shape()
    {
        cout << "~Shape..." << endl;
    }
};

class Circle : public Shape
{
public:
    void Draw()
    {
        cout << "Circle::Draw() ..." << endl;
    }
    ~Circle()
    {
        cout << "~Circle ..." << endl;
    }
};

class Square : public Shape
{
public:
    void Draw()
    {
        cout << "Square::Draw() ..." << endl;
    }
    ~Square()
    {
        cout << "~Square ..." << endl;
    }
};

class Rectangle : public Shape
{
public:
    void Draw()
    {
        cout << "Rectangle::Draw() ..." << endl;
    }
    ~Rectangle()
    {
        cout << "~Rectangle ..." << endl;
    }
};

void DrawAllShapes(const vector<Shape *> &v)
{
    vector<Shape *>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        (*it)->Draw();
    }
}

void DeleteAllShapes(const vector<Shape *> &v)
{
    vector<Shape *>::const_iterator it;
    for (it = v.begin(); it != v.end(); ++it)
    {
        delete(*it);
    }
}

// 简单工厂模式
class ShapeFactory
{
public:
    static Shape *CreateShape(const string &name)
    {
        Shape *ps = 0;
        if (name == "Circle")
        {
            ps = new Circle;
        }
        else if (name == "Square")
        {
            ps = new Square;
        }
        else if (name == "Rectangle")
        {
            ps = new Rectangle;
        }

        return ps;
    }
};

int main(void)
{
    //Shape s;      //Error,不能实例化抽象类
    vector<Shape *> v;
    //Shape* ps;
    //ps = new Circle;
    //v.push_back(ps);
    //ps = new Square;
    //v.push_back(ps);
    //ps = new Rectangle;
    //v.push_back(ps);

    Shape *ps;
    ps = ShapeFactory::CreateShape("Circle");
    v.push_back(ps);
    ps = ShapeFactory::CreateShape("Square");
    v.push_back(ps);
    ps = ShapeFactory::CreateShape("Rectangle");
    v.push_back(ps);

    DrawAllShapes(v);
    DeleteAllShapes(v);


    return 0;
}

Shape类是抽象类,Draw函数是纯虚函数,Circle, Square, Rectangle都重新实现了Draw,在这里把Shape的析构函数声明为虚函数,那么delete 基类指针,会调用派生类的析构函数,这样不容易造成内存泄漏。虚函数可以让我们以一致的观点看待从同一基类继承下来的派生类对象,都是通过Shape* 去调用Draw,但能够实现不同的行为。

三、多态优点

多态性有助于更好地对程序进行抽象

控制模块能专注于一般性问题的处理 具体的操作交给具体的对象去做

多态性有助于提高程序的可扩展性

可以把控制模块与被操作的对象分开 可以添加已定义类的新对象,并能管理该对象 可以添加新类(已有类的派生类)的新对象,并能管理该对象

四、虚析构函数

析构函数可以声明为虚函数

delete 基类指针; 程序会根据基类指针指向的对象的类型确定要调用的析构函数 基类的析构函数为虚函数,所有派生类的析构函数都是虚函数

构造函数不得是虚函数

如果要操作具有继承关系的类的动态对象,最好使用虚析构函数。特别是在派生类析构函数需要完成一些有意义的操作,比如释放内存 析构函数还可以是纯虚的。

#include <iostream>
using namespace std;


// 对于一个没有任何接口的类,如果想要将它定义成抽象类,只能将虚析构函数声明为纯虚的
// 通常情况下在基类中纯虚函数不需要实现
// 例外是纯虚析构函数要给出实现。(给出一个空的实现即可)
class Base
{
public:
    virtual ~Base() = 0
    {

    }
};

class Derived : public Base
{

};

int main(void)
{
    //  Base b; //error, 抽象类
    Derived d;
    return 0;
}

// 对于一个没有任何接口的类,如果想要将它定义成抽象类,只能将虚析构函数声明为纯虚的 // 通常情况下在基类中纯虚函数不需要实现 // 例外是纯虚析构函数要给出实现。(给出一个空的实现即可)

参考:

C++ primer 第四版 Effective C++ 3rd C++编程规范

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏别先生

java中集合类中Collection接口中的Map接口的常用方法熟悉

1:Map接口提供了将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。Map接口中同样提供了集合的常用方法。 2:由于Map集合中的元素...

21810
来自专栏编程

Python面向对象5:特殊方法

特殊方法,两边带双下划线的方法。比如__init__(self,...) 、__del__(self) 、__call__(self, *args) 、__st...

19510
来自专栏企鹅号快讯

Python网络爬虫之正则表达式

正则表达式非Python独有,在Python中通过re库模块实现。 ? 下面是一些常见的匹配模式 ? re.match re.match尝试从字符串的起始位置匹...

19310
来自专栏互联网杂技

javascript大法好,不用记

数组的操作 ---- Array.prototype.toString ( ) 把数组转变为字符串,返回字符串,arr.toString(); ---- Arr...

3717
来自专栏python学习指南

python正则表达式

本篇将介绍python正则表达式,更多内容请参考:【python正则表达式】 什么是正则表达式 正则表达式,又称规则表达式,通常被用来检索、替换那些符合某...

2556
来自专栏小鹏的专栏

用一个脚本学习 python

# -*- coding: utf-8 -*- # Python 2.7 学习参考脚本 # print 打印函数 print "Hello Worl...

2927
来自专栏PPV课数据科学社区

Python 正则表达式

? 简介 正则表达式(regular expression)是可以匹配文本片段的模式。最简单的正则表达式就是普通字符串,可以匹配其自身。比如,正则表达式 ‘h...

4156
来自专栏编程坑太多

Python正则表达式re模块简明笔记

1315
来自专栏测试开发架构之路

C++之面向对象的三个基本特征

三大特性是:封装,继承,多态   所谓封装 就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.封装是面...

2866
来自专栏Android开发指南

5:面向对象总结

37212

扫码关注云+社区

领取腾讯云代金券