c++多态相对于重定义的好处

这里先记一下这个问题,学的过程中很疑惑,因为自己是先学的python, python中的继承大部分都是重定义,所以比较好奇多态的有什么好处,为什么不用重定义而要用多态?

先记一下重写、重载、多态、重定义:
首先重写(override)和多态是一起的,重写是多态的具体实现方式;重载(overload)是针对一个类中的同名方法(但是方法的输入参数不一样),重定义和多态则是针对不同类中的同名方法,而多态的基类方法中有virtual,是用虚函数的方式实现的,而重定义则没有virtual,是直接覆盖基类中的方法。

采用多态而不是重定义的好处:
1、子类中的重定义会隐藏或者说覆盖基类里的同名函数,也就是说不能再调用父类里的同名函数了。以前的疑问是:既然我在子类里重新定义了一个,说明不想用以前的同名函数啊?但是,如果父类里有多个同名函数呢?比如发生了重载的情况,在子类中重定义了一个输入三个参数的同名函数,那要是父类里面有一个四个参数的同名函数想要使用呢?如果不用多态,那就使用不了了,因为同名函数全被覆盖了。
2、重定义没法通用调用(终于明白腾讯的一个学长给我解释的了)。重定义中的方法调用必须用children.move()的形式(假设方法是move),但是如果我就想用一个通用的move呢?用学长的话说,我不想管你子类里是啥,我就想让所有的子类都move().如下图(图截自老九课程):
在这里插入图片描述
如图所示,我管你子类是啥,反正我就这么个函数来调用。这就是我理解的通用调用,因为我们的子类可能有很多个,比如一百个,而且每个方法里不止是move,还有jump等等等等,难道每个都去写一次children.move()和children.jump()等等等等吗?不,不用,用上多态,加上virtual,只要一个上面的MoveRole(),各种各样的方法都可以放在MoveRole()里面,这就相当于打包处理了。在调用时只需要如下:
在这里插入图片描述
直需要输入子类名字,即可打包处理,如果只有一个方法,那么可能children.func()也行,但是如果方法很多的时候呢?重定义需要每一个方法都再码一遍,但是多态就不用了,给我个子类地址就OK了!!!

学java时的新理解(来自廖雪峰的课程):
对于“多态是指,针对某个类型的方法调用,其真正执行的方法取决于运行时期实际类型的方法。也就是运行期才能动态决定调用的子类方法。”的理解:

public void runTwice(Person p) {
    p.run();
}

如果我们直接看上述代码,并不知道p.run()会执行的是哪一个方法,因为虽然它传入的参数类型是Person,但是我们是无法知道传入的参数实际类型究竟是Person,还是Student,还是Person的其他子类,因此,也无法确定调用的是不是Person类定义的run()方法。
更深入的例子:

public class Main {
    public static void main(String[] args) {
        // 给一个有普通收入、工资收入和享受国务院特殊津贴的小伙伴算税:
        Income[] incomes = new Income[] {
            new Income(3000),
            new Salary(7500),
            new StateCouncilSpecialAllowance(15000)
        };
        //下面这里体现了多态,不管你传入的是Income还是Salary还是其它子类,都可以**通用调用**
        System.out.println(totalTax(incomes));
    }

    public static double totalTax(Income... incomes) {
        double total = 0;
        for (Income income: incomes) {
            total = total + income.getTax();
        }
        return total;
    }
}

class Income {
    protected double income;

    public Income(double income) {
        this.income = income;
    }

    public double getTax() {
        return income * 0.1; // 税率10%
    }
}

class Salary extends Income {
    public Salary(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        if (income <= 5000) {
            return 0;
        }
        return (income - 5000) * 0.2;
    }
}

class StateCouncilSpecialAllowance extends Income {
    public StateCouncilSpecialAllowance(double income) {
        super(income);
    }

    @Override
    public double getTax() {
        return 0;
    }
}

新增补充理解:
每次以为自己理解了,其实都没咋理解,哈哈哈哈哈。
最近的一个问题是,为什么要用声明父类,而实际new子类的方式,也就是为什么要向上转型,比如:

Person p = new student();

还在想为啥不直接student p = new student()。
说明我还是没弄懂多态(主要没实践过啊,唉),在多态调用的时候,我们用的就是父类声明出来的实例啊,比如最上面例子的hero,我们声明的时候就是用的Hero& hero,后面的例子,用的就是Income[] incomes都是通过直接声明父类的形式,而变化在于new的实际子类类型是不一致的。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值