【C++】虚函数与多态

这篇具有很好参考价值的文章主要介绍了【C++】虚函数与多态。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

多态

多态性是面向对象程序设计的重要特征之一,是指发出同样的消息被不同类型的对象接受时有可能导致完全不同的行为。多态的实现:函数重载、运算符重载、模板、虚函数。

静态绑定与动态绑定

静态绑定:绑定过程出现在编译阶段,在编译期就已经确定要调用的函数。
动态绑定:绑定过程工作在程序运行时执行,在程序运行时才确定要调用的函数。

虚函数

虚函数的概念:在基类中冠以关键字virtual的成员函数。
虚函数的定义:

virtual 函数类型 函数名称(参数列表);

如果一个函数在基类中被声明为虚函数,则他在所有的派生类中都是虚函数。只有通过基类指针或调用虚函数才能引发动态绑定。虚函数不能声明为静态。

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void Fun1()
    {
        cout << "Base::Fun1 ..." << endl;
    }
    virtual void Fun2()
    {
        cout << "Base::Fun2 ..." << endl;
    }
    void Fun3()
    {
        cout << "Base::Fun3 ..." << endl;
    }
};

class Derived :public Base
{
public:
    virtual void Fun1()

    {
        cout << "Derived::Fun1 ,,," << endl;
    }
    virtual void Fun2()
    {
        cout << "Derived::Fun2 ,,," << endl;
    }
    void Fun3()
    {
        cout << "Derived::Fun3 ..." << endl;
    }
};

int main()
{
    Base* p;
    Derived d;

    p = &d;
    p->Fun1();//Fun1是虚函数,基类指针指向派生类对象,调用的是派生类对象的虚函数
    p->Fun2();
    p->Fun3();//Fun3非虚函数,根据p指针实际类型来调用相应类的成员函数
    return 0;
}

虚析构函数

何时需要虚析构函数?当你可能通过基类指针删除派生类对象时,如果你打算允许其他人通过基类指针调用对象的析构函数(通过delete这样做是正常的),并且被析构的对象是有重要的析构函数的派生类的对象,就需要让基类的析构函数作为虚函数。

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void Fun1()
    {
        cout << "Base::Fun1 ..." << endl;
    }
    virtual void Fun2()
    {
        cout << "Base::Fun2 ..." << endl;
    }
    void Fun3()
    {
        cout << "Base::Fun3 ..." << endl;
    }
    Base()
    {
        cout << "Base ..." << endl;
    }
    virtual ~Base()
    {
        cout << "~Base ..." << endl;
    }
};

class Derived :public Base
{
public:
    virtual void Fun1()

    {
        cout << "Derived::Fun1 ,,," << endl;
    }
    virtual void Fun2()
    {
        cout << "Derived::Fun2 ,,," << endl;
    }
    void Fun3()
    {
        cout << "Derived::Fun3 ..." << endl;
    }
    Derived()
    {
        cout << "Derived ..." << endl;
    }
    //基类析构函数为虚函数   派生类不加virtual也为虚函数
    //如果一个类要作为多态基类,要将析构函数定义成虚函数
    virtual ~Derived()
    {
        cout << "~Derived ..." << endl;
    }
};

int main()
{
    Base* p;
    p = new Derived;

    p->Fun1();
    delete p;
    return 0;
}

虚表指针

虚函数的动态绑定是通过虚表来实现的。包含虚函数的类头4个字节存放指向虚表的指针。

object slicing与虚函数

#include <iostream>
using namespace std;

class CObject
{
public:
    virtual void Serialize()
    {
        cout << "CObject::Serialize ..." << endl;
    }
};

class CDocument : public CObject
{
public:
    int data1_;
    void func()
    {
        cout << "CDocument::func ..." << endl;
        Serialize();
    }
    void Serialize()
    {
        cout << "CDocument::Serialize ..." << endl;
    }
    CDocument()
    {
        cout << "CDocument()" << endl;
    }
    CDocument(const CDocument& other)
    {
        cout << "CDocument(const CDocument& other)" << endl;
    }
};

class CMyDoc : public CDocument
{
public:
    int data2_;
    void Serialize()
    {
        cout << "CMyDoc::Serialize ..." << endl;
    }
};

int main()
{
    CMyDoc mydoc;
    CMyDoc* pmydoc = new CMyDoc;
    cout << "#1 testing" << endl;
    mydoc.func();

    cout << "#2 testing" << endl;
    ((CDocument*)(&mydoc))->func();  

    cout << "#3 testing" << endl;
    pmydoc->func();

    cout << "#4 testing" << endl;
    ((CDocument)mydoc).func();//mydoc对象强制转换为CDocument对象  向上转型  完全将派生类对象转化成了基类对象
    return 0;
}

overload、overwrite、override

成员函数被重载的特征:

  • 相同的范围(在同一个类中);
  • 函数名字相同;
  • 参数不同;
  • virtual关键字可有可无。

覆盖是指派生类函数覆盖基类函数,特征是:

  • 不同的范围(分别位于派生类与基类);
  • 函数名字相同;
  • 参数相同;
  • 基类函数必须有virtual关键字。

重定义(派生类与基类)

  • 不同的范围(分别位于派生类与基类);
  • 函数名与参数都相同,无virtual关键字;
  • 函数名相同,参数不同,virtual可有可无。·

纯虚函数

虚函数实现多态性的前提。需要在基类中定义共同的接口,接口要定义为虚函数。如果基类的接口没办法实现怎么办,就将这些接口定义为纯虚函数。在基类中不能给出有意义的虚函数定义,这时可以把它说明成纯虚函数,把它的定义留给派生类来做。纯虚函数不用实现。定义纯虚函数:

class 类名{
	virtual 返回值类型 函数名(参数表) = 0}

抽象类

抽象类为抽象和设计的目的而声明,将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。抽象类只能作为基类来使用,不能声明抽象类的对象,构造函数不能是虚函数,析构函数可以是虚函数。抽象类不能用于直接创建对象实例,可以声明抽象类的指针和引用。可使用指向抽象类的指针支持运行时多态性。派生类中必须实现基类中的纯虚函数,否则它将被看作一个抽象类。

多态优点

  • 多态性有助于更好地对程序进行抽象。控制模块能专注于一般性问题的处理。具体的操作交给具体的对象去做。

  • 多态性有助于提高程序的可扩展性。可以把控制模块与被操作的对象分开。可以添加已定义类的新对象,并能管理该对象。可以添加新类(已有类的派生类)的新对象,并能管理该对象。

虚析构函数

析构函数可以声明为虚函数,delete基类指针程序会根据基类指针指向的对象的类型确定要调用的析构函数。基类的析构函数为虚函数,所有派生类的析构函数都是虚函数。构造函数不得是虚函数。如果要操作具有继承关系的类的动态对象,最好使用虚析构函数。特别是在析构函数需要完成一些有意义的操作比如释放内存时,析构函数还可以是纯虚的。

对于一个没有任何接口的类,如果想要将它定义成抽象类,只能将虚析构函数声明为纯虚的,通常情况下在基类中纯虚函数不需要实现,例外是纯虚析构函数要给出实现(给出一个空的实现即可)。文章来源地址https://www.toymoban.com/news/detail-497277.html

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

class Shape
{
public:
    virtual void Draw() = 0;
    virtual ~Shape() {};
};

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()
{
    //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);*/

    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;
}

到了这里,关于【C++】虚函数与多态的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • java特征:多态性

    对象的多态性 多态性,是面向对象中最重要的概念,在Java中的体现: 对象的多态性:父类的引用指向子类的对象 格式:(父类类型:指子类继承的父类类型,或者实现的接口类型) 举例: 对象的多态:在Java中,子类的对象可以替代父类的对象使用。所以,一个引用类型变

    2024年02月12日
    浏览(32)
  • Python 中的多态性

    多态性是 OOP 的一个特征,这意味着一个名称可以具有不同的功能。 单个实体可以采取不同的形式。 本篇文章将介绍如何在 Python 中实现多态性。 理解这一点的最佳方法是使用 len() 函数。 对于不同的对象,该函数有不同的解释。 对于列表,它将返回存在的总元素;对于字符

    2024年02月05日
    浏览(35)
  • 类的多态性(JAVA)

    目录 多态  重写  向上转型 类的多态性例子:  多态的优缺点   所有的OOP语言都会有三个特征: 封装(点击可跳转) 继承(点击可跳转) 多态 多态体现: 在代码运行时,当传递不同类对象时,会调用对应类中的方法。 在java中要实现多态,必须要满足如下几个条件,缺一

    2024年02月13日
    浏览(37)
  • Android java基础_多态性

    向上转换:只能定义被子类覆写的方法,不能调用在子类中定义的方法。 运行结果: JAVA向下转换的例子,在进行对象的向下转换前,必须首先发生对象的向上转换.否则会编译不过 运行结果: 看一下,下面的例子,假如有一千个类继承了father这个类,如果我们要打印他们的信

    2024年02月22日
    浏览(41)
  • C# 类class、继承、多态性、运算符重载,相关练习题

    34.函数重载 35.几个相同的函数  print() ,用于打印不同的数据类型。   36.基类和派生类   37.基类的初始化   38.多重继承   39.动态多态性   40.抽象性和虚方法   41.通过虚方法 area() 来计算不同形状图像的面积   42.运算符重载的实现   @www.runoob.com 

    2024年02月09日
    浏览(44)
  • 【C++庖丁解牛】面向对象的三大特性之一多态 | 抽象类 | 多态的原理 | 单继承和多继承关系中的虚函数表

    🍁你好,我是 RO-BERRY 📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 需要声明的,本节课件中的代码及解释都是在vs2013下的x86程序中,涉及的指针都是4bytes。如果要其他平台

    2024年04月10日
    浏览(57)
  • 【C++】面向对象之多态

    文章内的所有调试都是在vs2022下进行的, 部分小细节可能因编译器不同存在差异。 概念引入 对于一个火车票售票系统, 可能会有多重角色, 比如普通成人类、学生类、军人类、儿童类等等… 这些类可能都是从某个基类派生出来的, 而且每个类都有一个基本需求,就是买票

    2024年02月01日
    浏览(85)
  • C++ 面向对象三大特性——多态

    ✅1主页:我的代码爱吃辣 📃2知识讲解:C++ 继承 ☂️3开发环境:Visual Studio 2022 💬4前言:面向对象三大特性的,封装,继承,多态,今天我们研究研究 C++的多态 。 目录 一.多态的概念 二.多态的定义及实现 1.多态的构成条件 2. 虚函数 3.虚函数的重写 4. C++11 override 和 fina

    2024年02月12日
    浏览(63)
  • 【C++】面向对象---多态(万字详解)

           🔥🔥 欢迎来到小林的博客!!       🛰️博客主页:✈️小林爱敲代码       🛰️文章专栏:✈️小林的C++之路       🛰️欢迎关注:👍点赞🙌收藏✍️留言       今天给大家讲解多态,多态是面向对象的一个重要内容。也非

    2024年02月01日
    浏览(40)
  • c++面向对象之封装、继承、和多态

    把客观事物封装成类,而且可以把自己的数据和方法设置为只能让可信的类或者对象操作,对不可信的信息进行隐藏(利用public,private,protected,friend)实现 has-a :描述一个类由多个部件类构成,一个类的成员属性是另一个已经定义好的类。 use-a:一个类使用另一个类,通过类之间

    2024年02月02日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包