当前位置: 首页 > news >正文

函数的重写

我在OOP方面的知识一直都使用后再看理论的,因为之前的理论大多都没有吸收,也缺乏深入理解。最近又重新学习了继承体系中关于类中方法的重写(override)。先通过在C++下的例子来阐述这一机制。

#include<iostream> #include<string> using namespace std; class People{ public: People(string name){ this->name = name; } // void display(){ //不加virtual是普通成员函数 virtual void display(){ //加virtual变成虚函数 cout << "I am a people, name: " + name << endl; }; protected: string name; }; class Man : public People{ public: Man(string name, string wife):People(name){ this->wife = wife; } void display(){ cout << "I am a man, name: " + name + " wife: " + wife << endl;; }; protected: string wife; }; int main(){ // People p("baobei"); // p.diplay(); //输出:I am a people, name: baobei // Man m("baobei", "mbaobei"); // m.diplay(); //输出:I am a people, name: baobei wife: mbaobei People *p; p = new Man("baobei", "mbaobei"); p->display(); //输出:I am a people, name: baobei wife: mbaobei return 0; }


在上例中,函数display()不加virtual只是普通的成员函数,那么即使在Man继承People后重写了display(),那么在主函数中父类指针p指向子类对象,并调用其函数display(),并没有执行子类对象的display()函数,而是执行了基类的方法。而在基类People中display()函数前加上virtual后,程序则调用了子类的display()方法。

这就是虚函数在动态绑定中的作用。一个基类指针指向他的任何子类对象,都能够非常智慧的执行子类的方法,而不会被父类的方法所覆盖。这种需求在OOP中是非常普遍的。几乎每个程序员每天都在用吧。


疑问一:很多人都会问,在基类中不加virtual,子类依旧可以重写,而且编译没错,程序也能执行啊?

回答:那是你没读上面那个程序,如果不加virtual,子类方法肯定就被父类方法覆盖了,除非你专门弄一个对子类对象的直接引用。


疑问二:java程序员又会说,java中子类就可以任意重写父类实现著名的父类引用指向子类对象,调用子类方法,实现动态绑定。还不用什么virtual关键字?

回答:那还是你对java语言不熟悉,java中对应的关键字是"@override",呵呵,现在知道"@override"的作用了吧,以前一直都不管那个关键字。你试着将"@override"去掉看看,父类方法必然覆盖掉子类方法,也就是父类引用只能掉父类的方法,即使他指向子类对象。


疑问三:override是重写,那么overload是什么?两者有关系么?很多人容易混?

回答:override是子类重写父类的方法实现动态绑定。是继承体系中纵向的,而overload是函数重载,横向的,类体内部的。没什么关系。但都是多态的体现!

相关文章:

  • wx入门(一)
  • ZOJ 1649 Rescue BFS水题
  • Linux 性能分析的前 60 秒
  • C++继承体系下类中属性的能见度总结
  • 案例45-crm练习改写客户列表使用struts2OGNL
  • ZOJ 2913 Bus Pass BFS水题
  • 内置函数——format
  • POJ 1465 Multiple BFS
  • Jenkins之Linux和window配置区别
  • POJ Holedox Moving BFS hash判重
  • mysql5.7的安装
  • MySQL 5.7主从复制与主主复制实现细节分析
  • troubleshooting IMP-00032IMP-00008
  • 获取异常信息
  • POJ 2935 Basic Wall Maze BFS
  • JS 中的深拷贝与浅拷贝
  • Docker 笔记(2):Dockerfile
  • ECMAScript入门(七)--Module语法
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • idea + plantuml 画流程图
  • js作用域和this的理解
  • Mithril.js 入门介绍
  • spring security oauth2 password授权模式
  • 回顾2016
  • 简单实现一个textarea自适应高度
  • 警报:线上事故之CountDownLatch的威力
  • 聊聊directory traversal attack
  • 前端攻城师
  • 使用Gradle第一次构建Java程序
  • 思考 CSS 架构
  • 线性表及其算法(java实现)
  • # .NET Framework中使用命名管道进行进程间通信
  • #{} 和 ${}区别
  • #pragma 指令
  • #微信小程序:微信小程序常见的配置传旨
  • (07)Hive——窗口函数详解
  • (1)Map集合 (2)异常机制 (3)File类 (4)I/O流
  • (分布式缓存)Redis持久化
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)Sublime Text3配置Lua运行环境
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • .net core 控制台应用程序读取配置文件app.config
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net IOC框架入门之一 Unity
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • .netcore 获取appsettings
  • .net分布式压力测试工具(Beetle.DT)
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET轻量级ORM组件Dapper葵花宝典
  • /proc/interrupts 和 /proc/stat 查看中断的情况
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [].slice.call()将类数组转化为真正的数组
  • [23] GaussianAvatars: Photorealistic Head Avatars with Rigged 3D Gaussians