c++学习:多态

目录

什么时候用到多态

多态的作用

多态简单的理解

多态的分类

1. 函数重载,函数模板实现多态

2. 虚函数+继承实现多态

例子1

计算机类

加法类

乘法类

自定义使用多态的函数

主函数

例子2

先不用多态设计

矩形类

圆形类

主函数

使用多态来设计 计算图形面积

图形 基类

矩形类

圆形类

打印各个图形类对象的面积函数

主函数

注意


什么时候用到多态

当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态

多态的作用

调用成员函数时,会根据调用函数的对象的类型来执行不同的函数,同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果

多态简单的理解

用基类的指针指向子类的对象

多态的分类

1. 函数重载,函数模板实现多态

        同名函数不同返回值和不同参数叫做重载,重载也属于多态的一种

        属于静态多态,编译时多态

2. 虚函数+继承实现多态

        定义一个基类指针指向派生类对象,通过基类访问的是子类的虚函数

        属于动态多态,编译时多态

例子1

定义一个计算机类,一个加法类,一个乘法类,加法和乘法继承计算机类,在外面定义一个函数,

函数里打印加法类和乘法类里的计算结果,参数是计算机类的地址

计算机类

//设计一个计算器类 --基类
class AbstractCalc
{
public:
    AbstractCalc(int a,int b)
    {
        m_a = a;
        m_b = b;
    }
    //计算接口,定义一个统一的接口  -虚函数
    virtual int getResult()
    {
        return 0;
    }
protected: //本类和派生类可以使用
    int m_a;
    int m_b;
private:

};

加法类

//设计一个加法类
class AddCalc:public AbstractCalc
{
public:
    AddCalc(int a,int b):AbstractCalc(a,b)
    {

    }
    //定义一个函数,跟基类中的函数同名
    //在子类重写(重新实现)基类里面的虚函数(同名同参),那么原先继承过来的虚表里面记录的是 基类的虚函数的地址,现在替换为 子类同名的虚函数的地址,virtual只需要在基类写,派生类里可以省略
    virtual int getResult()
    {
        return m_a +m_b;
    }
    int data;
};

乘法类

//设计一个乘法类
class MulCalc:public AbstractCalc
{
public:
    MulCalc(int a,int b):AbstractCalc(a,b)
    {

    }
    //定义一个函数,跟基类中的函数同名
    virtual int getResult() override
    {
        return m_a * m_b;
    }
};

自定义使用多态的函数

//其实我们是希望这个基类指针 调用的是派生类的函数
//也就是说,希望运行的时候 检查的是  指针所指向的对象数据类型, 调用指针所指向对象的里面的函数成员
int calcResult(AbstractCalc *p) //AbstractCalc *p = &a1   AbstractCalc *p = &m1
{
    //此时编译器检查的是指针的数据类型,由于指针的数据类型是 基类的类型 AbstractCalc ,所以通过这个指针 调用的是 基类里面的函数
    cout<<p->getResult()<<endl;
}

主函数

int main()
{
    //直接调用函数,把对象直接当参数传入,就可以省一些事,不用自己打印,后面的派生类都可以这么实现
    AddCalc a1(10,20);
    calcResult(&a1);
    //cout<<a1.getResult()<<endl;

    MulCalc m1(10,20);
    calcResult(&m1);
    //cout<<m1.getResult()<<endl;

    return 0;
}

因为基类的getResult函数用virtual来修饰,表示虚函数,当继承了基类的派生类创建对象时,就会生成一个虚函数表,函数的地址就会存放在虚函数表里,当我们在派生类重写基类的getResult函数时,c++就会把重写后的函数地址替换掉虚函数表里的基类getResult函数地址,当我们调用的时候就会查到虚函数表的地址,进行调用所对应地址的函数。

例子2

先不用多态设计

计算图形面积,计算矩形的面积和圆形的面积

矩形类

//矩形类---面积
class Rectangle
{
public:
    Rectangle(int w,int h):m_width(w),m_height(h)
    {

    }
    ~Rectangle()
    {

    }
    double area()
    {
        return m_width * m_height;
    }
private:
    int m_width;
    int m_height;
};

圆形类

//圆形类--面积
class Circle
{
public:
    Circle(int r):m_r(r)
    {

    }
    ~Circle()
    {

    }
    double getarea(
    {
        return 3.14*m_r*m_r;
    }
private:
    int m_r;
};

主函数

int main()
{
    Rectangle r1(10,20);
    r1.area();

    Circle c1(10);
    c1.area();

    return 0;
}

这样子虽然可以算出来,但如果我们还要计算三角形,多边形,正方形的面积时,就会多很多个函数,我们就可以使用多态进行遍历

使用多态来设计 计算图形面积

图形 基类

//图形--基类
class Sharpe
{
public:
    Sharpe(){}
    ~Sharpe(){}

    //统一的接口 ---虚函数
    virtual double area(){return 0;}
};

矩形类

//矩形类---面积
class Rectangle:public Sharpe
{
public:
    Rectangle(int w,int h):m_width(w),m_height(h)
    {

    }
    ~Rectangle()
    {

    }
    virtual double area() override//virtual和override可以省略
    {
        return m_width * m_height;
    }
private:
    int m_width;
    int m_height;
};

圆形类

//圆形类--面积
class Circle:public Sharpe
{
public:
    Circle(int r):m_r(r)
    {

    }
    ~Circle()
    {

    }
    double area() override
    {
        return 3.14*m_r*m_r;
    }
private:
    int m_r;
};

打印各个图形类对象的面积函数


//基类的指针或者引用 指向派生类对象 ,调用的是 派生类的虚函数 ---动态多态
void print_area(Sharpe &p) //Sharpe *p =&r1     Sharpe *p =&c1
{
    cout<<p.area()<<endl;
}

主函数

int main()
{
    Rectangle r1(10,20);
    print_area(r1);

    Circle c1(10);
    print_area(c1);

    return 0;
}

这样只需要调用函数把对象传入就可以直接得出答案,方便很多

注意

  1. 必须首先在基类中定义虚函数
  2. 定义一个基类指针指向派生类对象,通过基类访问的是子类的虚函数
  3. 派生类对应基类的虚函数的关键字可以省略
  4. 一般通过基类指针访问虚函数时才能体现多态性
  5. 子类重新实现重写父类中的虚函数,必须返回值函数名参数一致才叫重写
  6. 如果基类有标志虚函数,派生类没有定义该函数,就没有意义

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小白

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值