C++基础-虚函数/纯虚函数/普通函数

来源:互联网 发布:人类实验室 网络暴力 编辑:程序博客网 时间:2024/06/10 21:31

序言

本文主要内容:虚函数 + 纯虚函数 + 普通函数 + 虚函数纯虚函数的区别


1. 虚函数

  • 什么是虚函数

    • 被virtual关键字修饰的成员函数,就是虚函数
  • 为什么要使用虚函数

    • 引入虚函数主要为了实现重写多态

    • 虚函数主要作用是为了实现“动态多态性”,父类提供虚函数的实现,为子类提供默认的函数实现。子类可以重写父类的虚函数实现子类的特殊化

  • 说明

    • 对于虚函数来说,父类和子类都有各自的版本,由多态方式调用的时候动态绑定。
    • 虚函数必须实现,否则在链接时将会报错


2. 纯虚函数

  • 什么是纯虚函数

    • virtual returnType function() = 0;
  • 为什么要使用纯虚函数

    • 也是为了实现“动态多态性
    • 在很多情况下,基类本身生成对象是不合情理的,动物基类可以派生出老虎、孔雀等,但是动物本身的对象却没有实际意义,所以引入了纯虚函数
  • 什么情况下使用纯虚函数

    • 在基类中抽象出一个方法,且该基类只能被继承不能被实例化
    • 这个方法必须在派生类中被实现。

    满足以上两点,可考虑声明为纯虚函数。


3. 普通函数

  • 类的普通成员函数。

  • 父类为子类提供了普通函数的强制实现

  • 普通函数是静态编译的,可类内重载但没有运行时多态,只会根据指针引用的“字面值”类对象,调用自己的普通函数。


4. 虚函数和纯虚函数举例


  • [1] 普通函数举例(静态联编)
/* 例1 */class A{    public:        void funPrint()        {            cout<<"function in class A"<<endl;        }};class B:public A{    public:        void funPrint()      //重定义        {            cout<<"function in class B"<<endl;        }};int main(){    A *p;      //基类指针    A a;       //基类对象    B b;       //派生类对象    p = &a;    p->funPrint();    p = &b;    p->funPrint();    b.funPrint();    b.A::funPrint();   return 0;}//输出结果:    function in class A    function in class A    function in class B    function in class A//原因:1)静态联编:编译器在编译时就确定好了函数调用    (2)只是普通函数“重定义”,不管引用的实例是哪个类的,调用的时候系统会调用 “左值” 那个对象所属类的方法    >>> 所以基类A指针p最终调用类A的funPrint()函数,输出两个function in class A    >>> 类B实例调用类B的funPrint()函数,类B加上作用域操作符A::调用类A的funPrint()函数/* 例2 */#include <iostream>using namespace std;class A{    public:        virtual void fun1() = 0;             //纯虚函数        virtual ~A(){};        virtual void fun2()                  //虚函数        {            cout<<"fun1 in class A"<<endl;        }        void fun3()                          //普通成员函数        {            cout<<"fun3 in class A"<<endl;        }};class B:public A{    public:        virtual ~B(){};    void fun1()                              //纯虚函数实现    {        cout<<"fun1 in class B"<<endl;    }    void fun2()                              //虚函数重写(覆盖)    {        cout<<"fun2 in class B"<<endl;    }    void fun3()                              //普通函数重定义    {        cout<<"fun3 in class B"<<endl;    }};int main(){    A *a = new B;     //抽象类定义指针    a->fun1();    a->fun2();    a->fun3();    cout<<"*******************"<<endl;    B b;               //派生类实例化    b.fun1();    b.fun2();    b.fun3();    delete a;         //释放 new 的对象    return 0;}//输出结果:    fun1 in class B           //纯虚函数在基类中声明在子类中实现    fun2 in class B           //动态联编:多态。虚函数在子类中重写,运行时动态绑定    fun3 in class A           //静态联编:编译时就确定好了调用哪个函数。调用左值所属类的方法    *******************    fun1 in class B    fun2 in class B           //动态联编:多态。虚函数在子类中重写,运行时动态绑定    fun3 in class B           //静态联编:调用左值所属类的方法


  • [2] 虚函数举例(动态联编)
class A{    public:        virtual void funPrint()        {            cout<<"function in class A"<<endl;        }};class B:public A{    public:        void funPrint()    //或virtual void funPrint(),重写        {            cout<<"function in class B"<<endl;        }};int main(){    A *p;      //基类的指针    A a;    B b;    p = &a;    p->funPrint();    p = &b;    p->funPrint();    return 0;}//输出结果:    function in class A    function in class B//原因:1)动态联编:根据实例的不同动态决定调用哪个函数    (2)虚函数的唯一目的就是为了实现多态(动态多态性),编译时不确定调用哪个函数,而是动态的决定要调用哪个函数,即“运行时多态”    >>> 所以基类A指针p指向类A的实例a就调用类A的funPrint()函数,    >>> 指向类B的实例b就调用类B的funPrint()函数


  • [3] 纯虚函数举例(抽象类)

    纯虚函数通常存在于抽象类中,在基类中只是声明一个函数但不去实现它,让派生类去实现

class Vehicle{    public:        virtual void PrintTyre() = 0; //纯虚函数};class Car:public Vehicle{    public:        virtual void PrintTyre()        {            cout<<"Car tyre four"<<endl;        }};class Bike:public Vehicle{    public:        virtual void PrintTyre()        {            cout<<"Bike tyre two"<<endl;        }};int main(){   Car c;   Bike b;   b.PrintTyre();   c.PrintTyre();   return 0;}//输出结果:    Car tyre four    Bike tyre two//原因:1)定义vehicle类,但是具体每种交通工具有多少个轮子是不一定的,就定义为纯虚函数、留待派生类中具体实现


5. 虚函数和纯虚函数的联系与区别

  • 联系

    • 虚函数和纯虚函数可以定义在同一个类中

    • 虚函数和纯虚函数都可以在子类中被重写,以多态的形式调用

    • 虚函数和纯虚函数通常存在于抽象基类中,被子类继承,目的是提供一个统一的接口

    • 虚函数和纯虚函数的定义中不能有static标识符,因为static要求编译时即绑定,而虚函数和纯虚函数运行时才绑定(动态多态性)

    • 实现了纯虚函数的子类,该纯虚函数在子类中就变成了虚函数,子类的子类即孙子类可以覆盖(重写)该虚函数,由多态方式调用的时候动态绑定

  • 区别

    • 定义

      • 虚函数virtual returnType function();

      • 纯虚函数virtual returnType function() = 0;

    • 抽象类

      • 含有纯虚函数的类称为抽象类,而只含有虚函数的类不能称为抽象类

      • 抽象类不能实例化,但可以定义抽象类的指针引用(见例2)

    • 使用

      • 虚函数可以直接使用,也可以子类重写后以多态形式调用

      • 虚函数在基类中只有声明没有定义,是对子类的约束,是“接口继承”,必须在子类中实现该函数才可以使用



Acknowledgements:
http://www.cnblogs.com/xudong-bupt/p/3570304.html
http://www.cnblogs.com/fzhe/archive/2013/01/02/2842513.html
http://blog.chinaunix.net/uid-26851094-id-3327323.html
http://www.cnblogs.com/crazyacking/p/5265634.html(推荐)
http://www.cnblogs.com/bluestorm/archive/2012/08/29/2662350.html

2017.09.28

原创粉丝点击