多态和虚函数

多态

实现程序的统一性,多态分为编译时多态(重载),运行时多态(覆盖)。

实现手段:(父类的指针、引用和virtual)

1、父类的指针,指向子类
2、父类的对象,等于子类的对象
3、父类的引用,等于子类的对象

#include<iostream>
using namespace std;
class Base
{
public:
    void show()
    { cout<<" This is Base show()"<<endl;}
};
class Child:public Base
{
public:
    void show()
    {cout<<" This is Child show()"<<endl;}
};
void main()
{
    Child c;
    Base *bp=&c;
    Base &b=c;
    Base ba=c;
    bp.show();
    b.show();
    ba.show();
}

这里写图片描述

这里写图片描述
因此,若要实现多态性,应该通过覆盖和重载实现。利用虚函数实现覆盖。

#include<iostream>
using namespace std;
class Base
{
public:
    virtual void show()
    { cout<<" This is Base show()"<<endl;}
};
class Child:public Base
{
public:
    virtual void show()
    {cout<<" This is Child show()"<<endl;}  
};
void main()
{
    Child c;
    //实现多态的三种方式
    Base *bp=&c;
    //Base &b=c;
    //Base ba=c;

    //This is Child show()
     bp.show();
}

1、虚函数的声明和有缘函数一样,声明时,加上关键字,在类外实现时,不需要关键字;在类里面实现时,需要加上关键字。

2、实现多态后,基类一旦声明为虚函数,子类的同名同参同返回值类型,也一定虚函数,子类中的virtual有无不影响。

虚函数

一个函数的前面加上关键字virtual,会构成虚函数。

#include<iostream>
using namespace std;

class Base
{
public:
    Base()
    {}
    ~Base()
    {}
public:
    virtual void  Eat()
    { cout<<"This is Base Eat()"<<endl;}
    virtual void Sleep()
    {cout<<"This is Base Sleep()"<<endl;}
private:
    int m_x;
};

void main()
{
    Base b;
}

这里写图片描述

虚表保存了虚函数的地址

#include<iostream>
using namespace std;

class Base
{
public:
    Base():m_y(0)
    {}
    ~Base()
    {}
public:
    virtual void  Eat()
    { cout<<"This is Base Eat()"<<endl;}
    virtual void Sleep()
    {cout<<"This is Base Sleep()"<<endl;}
private:
    int m_y;
};
class Child:public Base
{
public:
    Child():m_x(0)
    {}
    ~Child()
    {}
public:
     void Eat()
    {cout<<"This is Chid Eat()"<<endl;}
     void Sleep()
    {cout<<"This is Child Sleep()"<<endl;}
private:
    int m_x;
};
void main()
{
    //构造子类对象,先调用基类对象,基类中有虚函数,因此会有__vfptr,有虚表,保存了所有基类虚函数的地址
    Child p;
    Base *pa=&p;
    //This is Chid Eat() 原因如下
    pa->Eat();
}

这里写图片描述

过程:
这里写图片描述

虚表的情况:

1、子类虚函数函数覆盖了基类虚函数时,子类和基类各有一个虚表信息,并且最 终子类的虚函数会覆盖基类的虚函数
2、子类虚函数,没有覆盖基类的虚函数,会把子类的虚函数保存在基类虚表后面
3、子类多继承基类 没有覆盖时,会把子类的虚函数保存到第一个基类的虚表中
4、子类多继承基类时,子类覆盖了基类的虚函数,会把子类在内阁虚表中都保存一份

纯虚函数

概念:

纯虚函数:基类不具体实现其成员函数(这种类也叫抽象类),主要用于派生子类,不能实例对象,可以定义指针

格式:virtual 返回值类型 函数名 参数列表 = 0;

声明:
当一个具体类继承纯虚函数时,在该类中必须完全实现基类中所有的纯虚函数,该类才可以实例对象。

#include<iostream>
using namespace std;
class Animal 
{
//抽象类
public:
    Animal()
    {}
    ~Animal()
    {}
public:
    //纯虚函数
    virtual void Eat()=0;
    virtual void Sleep()=0;
};
class Person:public Animal
{
public:
    Person()
    {}
    ~Person()
    {}
public:
    virtual void Eat()
    { cout<<"This is Person Eat()."<<endl;}
    //若不是全部实现基类的纯虚函数,则子类对象pp不能构造
    //virtual void Sleep()
    //{ cout<<"This is Person Sleep()"<<endl;}
};
int main()
{
    //子类的对象
    Person pp;  
}

抽象类的作用,为子类提供公共接口

#include<iostream>
using namespace std;
class Animal 
{
public:
    Animal()
    {}
    ~Animal()
    {}
public:
    virtual void Eat()=0;
    virtual void Sleep()=0;
};
class Person:public Animal
{
public:
    Person()
    {}
    ~Person()
    {}
public:
    virtual void Eat()
    { cout<<"This is Person Eat()."<<endl;}
    virtual void Sleep()
    { cout<<"This is Person Sleep()"<<endl;}
};
class Dog:public Animal
{

public:
    virtual void Eat()
    { cout<<"This is Dog Eat()."<<endl;}
    virtual void Sleep()
    { cout<<"This is Dog Sleep()"<<endl;}
};
//用为子类提供公共接口来实现不同功能,基类可以定义指针
void fun(Animal *aa)
{
    aa->Eat();
    aa->Sleep();
}
int main()
{
    Person pp;
    Dog dog;    
    fun(&pp);
    fun(&dog);
}

这里写图片描述

总结:

1、虚函数中移动有虚表,且用一个虚指针指向虚表
2、满足覆盖的条件:父类为虚函数,子类也为虚函数,用子类的虚函数去覆盖了基类的函数
3、纯虚方法,是为了派生子类,为子类提供公共的接口
4、多态的两种表现,通过基类的指针、和引用方式来实现多态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值