博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++中virtual关键字的作用与Java中多态的一点对比
阅读量:6293 次
发布时间:2019-06-22

本文共 2282 字,大约阅读时间需要 7 分钟。

动机

最近一直在使用C++写win32程序,用了一些库,里面提供的类和demo各种是virtual这个关键字,一直不是很明白到底是啥用,于是查看了一些文档,写小程序来实验它的作用。

结论

virtual这个关键字的发挥作用是在子类去继承父类的时候。比如:

class Person{public:    void foo1()    {        // do ...    }        virtual void foo2()     {        // do ...    }};

像上面的代码,如果类Person就一直被实例化使用,但是没有类去继承它的话,那么这个virtual实际上并没有什么卵用。foo2()方法和foo1()是一样的。

当它被继承的时候,有两种情况,覆写(override)这个foo2()方法,或者不覆写它。比如这样:

class Student : public Person{public:    void foo2() { // do something.. }};class Teacher : public Person{public:    // no override};

然后我们使用的时候,如果是子类的实例,调用foo2()方法,理所当然是执行子类中所定义的foo2()方法体。但是当将这个子类的实例强制转型成父类的实例(指针),再去执行foo2()方法的时候,对应的两种情况:子类实现了父类中virtual方法的,调用子类的方法;子类中没有override的,仍然是调用父类中的实现(这不是废话么……)

列个表格大概是这样:

// 大前提是父类中有个`virtual`方法`foo2()`        是否override foo2()    调用子类实例的foo2()    强转成父类后调用foo2()子类1          是                执行子类1的foo2()        执行子类1的foo2()子类2          否                执行父类的foo2()         执行父类的foo2()// 另一种情况// 大前提是父类中有个方法`foo2()`,但是没有virtual关键字修饰        是否override foo2()    调用子类实例的foo2()    强转成父类后调用foo2()子类1          是                执行子类1的foo2()        执行父类的foo2()子类2          否                执行父类的foo2()         执行父类的foo2()

与Java的对比

我的感觉好像Java自带这个多态的特性,不需要用什么关键字修饰,某个实例转换成父类后调用方法,默认就会调用子类的实现(如果有的话)。写了个小demo实验了一下,果然如此。

public class Main {    public static void main(String[] args) {        Person p = new Person();        p.foo(); // output: Person foo                Student s = new Student();        s.foo(); // output: Student foo                Person ps = s;        ps.foo(); // output: Student foo    }        static class Person {                public void foo() {            System.out.println("Person foo");        }    }        static class Student extends Person {                public void foo() {            System.out.println("Student foo");        }    }}

在《Effective Java 2e》中,作者也说了,尽可能的在申明,传参,返回值的时候使用父类和接口,而不要使用实现类。

大概是这样:

ArrayList
strList = new ArrayList
(); //这样是耿直的写法List
strList = new ArrayList
(); //这样更好,因为你可以换后面这个new// 返回值和参数也是一样,一般能使用接口就尽量使用接口,而不要写死成实现类,这样带来更大的灵活性public List
buildStrList(List
raw, AnyInterface interf) { // do xxxx}

总结

  • virtual关键字修饰的方法在子类继承实现后,就可以达到多态的目的(使用父类的指针依然可以调用到子类的实现)。

  • Java中不需要这个关键字来达到多态,覆写方法自带这个功能。

参考

转载地址:http://chcta.baihongyu.com/

你可能感兴趣的文章
失手打死请自己吃饭的酒友 嫌疑人在深圳落网
查看>>
数据分析师常用的十种数据分析思路,你都知道吗?
查看>>
特斯拉Model3交付危机:周产5000辆仍需排队一年,造空者花式补刀
查看>>
客户端单周发版下的多分支自动化管理与实践
查看>>
Flutter初体验(二)—— 创建第一个Flutter APP
查看>>
「起点订阅页」Checkbox 美化引发的蝴蝶效应
查看>>
Swift iOS : 模糊化
查看>>
Android 应用防止被二次打包指南
查看>>
高级篇:独立开发者 5 分钟入门 ASO
查看>>
深度有趣 | 18 二次元头像生成
查看>>
Android P 凹口屏支持,打造全面屏体验
查看>>
小白聊「区块链」
查看>>
源码|并发一枝花之CopyOnWriteArrayList
查看>>
循环神经网络
查看>>
从JDK源码角度看Long
查看>>
你不曾见过的酷炫地图可视化作品(一)
查看>>
二线城市疯狂抢人,技术人才何去何从?
查看>>
如果想成为一名顶尖的前端,这份书单你一定要收藏!
查看>>
iOS Swift UISearchController的取消按钮
查看>>
MyBatis 框架系列之基础初识
查看>>