zoukankan      html  css  js  c++  java
  • C++基础知识 基类指针、虚函数、多态性、纯虚函数、虚析构

    一、基类指针、派生类指针

    父类指针可以new一个子类对象

    二、虚函数

    有没有一个解决方法,使我们只定义一个对象指针,就可以调用父类,以及各个子类的同名函数?

    有解决方案,这个对象指针必须是一个父类类型,我们如果想通过一个父类指针调用父类、子类中的同名函数的话,这个函数是有要求的;

    在父类中,eat函数声明之前必须要加virtual声明eat()函数为虚函数。

    一旦某个函数被声明为虚函数,那么所有派生类(子类)中eat()函数都是虚函数。

    为了避免你在子类中写错虚函数,在C++11中,你可以在函数声明中增加一个override关键字,这个关键字用在子类中,而且是虚函数专用。

    override就是用来说明派生类中的虚函数,你用了这个关键字之后,编译器就会认为你这个eat是覆盖了父类中的同名函数(只有虚函数才存在子类可以覆盖父类中同名函数的问题),那么编译器就会在父类中找同名的虚函数,如果没找到,编译器就会报错,如果你不小心在子类中把虚函数写错了名字,写错了参数,编译器能够帮你进行纠错。

    final也是虚函数专用,用在父类中,如果我们在父类的函数声明中加了final,那么任何尝试覆盖在函数的操作都会引发错误。

    调用虚函数执行的是“动态绑定”。动态表示我们程序运行的时候才能知道调用了那个子类的中的eat()虚函数。

    动态的绑定到Men上去,还是Women上去,取决于newMen还是Women

    动态绑定:运行的时候才决定你的phuman对象绑定到那个eat()函数上运行。

    三、多态性

    多态性只是针对虚函数来说的;

    多态性:体现在具有继承关系的父类和子类之间,子类重新定义(重写)父类的成员函数eat(),同时父类把这个eat()函数声明为virtual虚函数;

    通过父类的指针,只有到了程序运行时期,找到动态绑定到父类指针上的对象,这个对象有可能是某个子类对象,也可能是父类对象;

    然后系统内部实际上是要查找一个虚函数表,找到函数eat()的入口地址,从而调用父类或子类的eat()函数,这就是运行时的多态性。

    四、纯虚函数

    纯虚函数是在基类中声明的函数,但是他在基类中没有定义,但是要求任何派生类都要定义该虚函数自己的实现方法;

    基类中实现纯虚函数的方法使在函数原型后面增加 =0;

    一旦一个类中又纯虚函数,那么你就不能生成这个类的对象了;

    抽象类不能用来生成对象,主要目的是用来同意管理子类对象;

    1)纯虚函数的类叫做抽象类,不能用来生成该类对象,主要用于当做基类来生成子类用的;

    2)子类必须要实现该基类中定义纯虚函数;

    五、基类的析构函数一般写成虚函数(虚析构函数)

    用基类指针new子类的对象,在delete的时候,系统不会调用派生类的析构函数,存在问题;

    解决方案:将基类的析构函数声明为虚析构函数;

    public继承中,基类对派生类及其对象的操作,只能影响那些从基类继承下来的成员,如果想要用基类对非继承的成员进行操作,则要把基类的这个函数定义为虚函数,析构函数也为虚函数,基类中的析构函数的虚属性也会被派生类继承,即派生类的析构函数也为虚函数。

    Human这个类中的析构函数就要声明为virtual的,也就是说C++11中为了获得运行时多态,所调用的成员必须是virtual的。

    如果一个类想要做基类,我们必须将类的析构函数声明为virtual虚函数;

    只要基类中的析构函数为虚函数,就能保证我们delete基类指针时能够运行正确,不会出现内存泄漏。

    虚函数会增加内存开销,类里面定义虚函数,编译器就会给这个类增加虚函数表,在这个表里存放虚函数的指针。

    本节案例:

    // Human.h
    // 头文件防卫式声明
    #ifndef __HUMAN__
    #define __HUMAN__
    
    #include "stdafx.h"
    class Human
    {
    public:
        Human();
        virtual ~Human();
    
    public:
        virtual void eat();
        virtual void eat2() = 0;
    };
    
    #endif
    
    // Human.cpp
    #include "stdafx.h"
    #include "Human.h"
    #include <iostream>
    
    Human::Human()
    {
        std::cout << "调用了Human::Human()" << std::endl;
    }
    
    void Human::eat()
    {
        std::cout << "人类喜欢吃各种美食" << std::endl;
    }
    
    Human::~Human()
    {
        std::cout << "调用了Human::~Human()" << std::endl;
    }
    
    // Men.h
    #ifndef __MEN__
    #define  __MEN__
    
    #include "stdafx.h"
    #include "Human.h"
    
    class Men : public Human
    {
    public:
        Men();
        ~Men();
    public:
        virtual void eat() override;
        virtual void eat2();
    };
    
    #endif
    
    // Men.cpp
    #include "stdafx.h"
    #include "Men.h"
    #include <iostream>
    
    void Men::eat()
    {
        std::cout << "男人喜欢吃米饭" << std::endl;
    }
    
    void  Men::eat2()
    {
        std::cout << "男人喜欢吃米饭2" << std::endl;
    }
    
    Men::Men()
    {
        std::cout << "调用了Men::Men()" << std::endl;
    }
    
    Men::~Men()
    {
        std::cout << "调用了Men::~Men()" << std::endl;
    }
    
    // Women.h
    #ifndef __WOMEN__
    #define  __WOMEN__
    #include "stdafx.h"
    #include "Human.h"
    class Women : public Human
    {
    public:
        Women();
        ~Women();
    
    public:
        virtual void eat() override;
        virtual void eat2() override;
    };
    
    #endif
    
    // Women.cpp
    #include "stdafx.h"
    #include "Women.h"
    #include <iostream>
    
    Women::Women()
    {
        std::cout << "调用了Women::Women()" << std::endl;
    }
    
    Women::~Women()
    {
        std::cout << "调用了Women::~Women()" << std::endl;
    }
    
    void Women::eat()
    {
        std::cout << "女人喜欢吃面食" << std::endl;
    }
    
    void Women::eat2()
    {
        std::cout << "女人喜欢吃面食2" << std::endl;
    }
    
    // main.cpp
    // Project3.cpp : 定义控制台应用程序的入口点。
    //
    
    #include "stdafx.h"
    #include <iostream>
    #include "Human.h"
    #include "Men.h"
    #include "Women.h"
    
    using namespace std;
    
    int main()
    {
        Human *phuman = new Men;
        phuman->eat();  // 男人喜欢吃米饭
        delete phuman;
    
        phuman = new Women;
        phuman->eat(); // 女人喜欢吃面食
        delete phuman;
    
        //phuman = new Human;
        //phuman->eat(); // 人类喜欢吃各种美食
        //delete phuman;
        phuman = new Men;
        phuman->eat2();  // 男人喜欢吃米饭
        delete phuman;
    
        phuman = new Women;
        phuman->eat2(); // 女人喜欢吃面食
        delete phuman;
    
        //Men men;
        Men *pmen = new Men;
        delete pmen;
    
        Human *phuman1 = new Men;
        delete phuman1;  // 没有执行子类的析构函数
    
        return 0;
    }
  • 相关阅读:
    JQuery帮助文档整理
    将table信息导出到excel
    jquery 选择器
    程序不小心出现死锁的解决方法
    兼容IE firefox 的全英文自动换行
    第三周2
    Jquery操作Select集锦
    Silverlight初学之:如果调用Silverlight项目中不同的控件
    【转载】很好的解决了asp.net页面ViewState过大的问题
    js得到url的各个部分【转】
  • 原文地址:https://www.cnblogs.com/hs-pingfan/p/10486316.html
Copyright © 2011-2022 走看看