C++虚函数和纯虚函数的区别

C++里,有虚函数也有纯虚函数,这两个概念名字很像,但是作用却不同,下面讲一下这两个概念的区别。

虚函数

虚函数主要是用在多态方面。虚函数是在基类中声明函数为virtual,并在子类中重写的函数,虚函数可以通过基类类型的指针调用子类里被重写的虚函数,可以实现多态。
我们先来看一看不用虚函数的情况:

子类函数屏蔽基类函数

#include <iostream>

using namespace std;


class Base 
{
  public:
    void hello()
    {
        cout << "hello world Base" << endl;

    }
};


class Derived : public Base 
{
  public:
   void hello()
   {
        cout << "hello world Derived" <<endl;
   }
};


int main()

{
    Base b;
    Derived d;

    b.hello(); 
    d.hello();
   /*******
   运行结果
    hello world Base
    hello world Derived
    ********/



    Base *b1;
    Base *b2;
    b1 = &b;
    b2 = &d; 

    b1->hello();
    b2->hello();
     /*******
    运行结果
    hello world Base
    hello world Base
    ********/

}

使用虚函数实现多态

可以看到,虽然把子类类型的值赋给了基类类型指针b2,但是b2->hello()这代码的结果仍然是调用了基类的hello()方法,这是因为,基类指针只能访问对象的基类部分,所以无法调用子类里的hello方法。

这样的话,我们要实现多态,就需要使用虚函数了,将上面的代码稍微改动一下。只需要在基类的hello()方法里前添加关键字virtual就行了。

#include <iostream>

using namespace std;


class Base 
{
  public:
    void hello()
    {
        cout << "hello world Base" << endl;

    }
};


class Derived : public Base 
{
  public:
   virtual void hello()
   {
        cout << "hello world Derived" <<endl;
   }
};


int main()

{
    Base b;
    Derived d;

    b.hello(); 
    d.hello();
   /*******
   运行结果
    hello world Base
    hello world Derived
    ********/



    Base *b1;
    Base *b2;
    b1 = &b;
    b2 = &d; 

    b1->hello();
    b2->hello();
     /*******
    运行结果
    hello world Base
    hello world Derived
    ********/

}

可以看到,通过虚函数,我们实现了多态。那么虚函数的大致工作原理是什么呢?

虚函数工作原理

先说明下,创建派生类的时候,先调用基类的构造函数,再调用子类的构造函数,一个派生类在内存中大概是这样的:

一一一一一一一
Base
一一一一一一一

Derived
一一一一一一一

Base部分和Derived部分是连接在一起的。两个一起组成了子类对象。
每一个类都有一个虚函数表(v-table),每个对象都有一个虚函数指针(vptr),指向虚函数表。当子类对象被创建后,虚函数指针就会指向子类中覆盖的虚函数。当使用基类指针时,虚函数指针将根据基类指针指向的对象的实际类型,来指向正确的函数。

当然,这个只是大概的步骤,虚函数在每本C++书里都会有介绍,如果想要更详细,深入的了解虚函数,可以去看看一些C++的经典著作。

纯虚函数

定义

纯虚函数是一种特殊的虚函数,它在基类中声明,却只能在派生类中给实现。在基类中声明纯虚函数的语法为:
 virtual void hello() = 0;

引入原因

因为C++没有接口这个关键字,我们想要规定一个类的行为的时候,就需要使用纯虚函数来解决问题,因为虚函数没有要求子类强制重写基类的方法,所以说无法靠虚函数规定子类的行为。而纯虚函数可以要求子类强制重写基类的纯虚方法。含有一个或者多个纯虚函数的类称为抽象类,抽象类无法被实例化。

代码

class IBreath
{
    public: 
    virtual void breath() = 0;
};

class Person : public IBreath
{
    public:
     void breath()
     {
         cout << "breathing...... " << endl;
     }
};

int main()

{

   Person p;
   p.breath();
   // 运行结果:breathing......
}

假如我们有一个Person类,这个类的所有对象要有一个呼吸的动作,我们声明了一个抽象类IBreath,里面有一个纯虚函数breath(),之后通过Person继承了这个抽象类,强制实现了breath()函数。

总结

可以看出,虚函数可以让子类继承并重写方法,但是没有强制的要求,而纯虚函数强制子类重写该函数,所以,纯虚函数总被当成接口来使用,而虚函数可以在实现多态的时候使用。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值