C++虚函数【Java有虚函数吗?】
1,简单介绍
定义在基类中的函数,子类必须对其进行覆写!【必须对其进行覆写?!】——Java中的接口、Abstract方法中的抽象类也有这样的要求。
C++中定义:
virtual void deal();//子类必须要对这个函数进行覆写
2,主要作用
(1)定义子类对象,并调用对象中未被子类覆盖的基类函数A。同时在该函数A中,又调用了已被子类覆盖的基类函数B。那此时将会调用基类中的函数B,可我们本应该调用的是子类中的覆盖函数B。虚函数即能解决这个问题。
①没有使用虚函数的例子:
#include<iostream>
using namespace std;
class Father //基类 Father
{
public:
void display() {cout<<"Father::display()\n";}
//在函数中调用了,子类覆盖基类的函数display()
void fatherShowDisplay() {display();}
}; class Son:public Father //子类Son
{
public:
//重写基类中的display()函数
void display() {cout<<"Son::display()\n";}
}; int main()
{
Son son; //子类对象
son.fatherShowDisplay(); //通过基类中未被覆盖的函数,想调用子类中覆盖的display函数
}
输出结果为:Father::display()
期望出现的结果应该为:Son::display
问题出现啦:
子类Son继承父类Father,并且覆写了父类中的dispaly方法,讲道理我们后续调用子类中的dispaly方法应该想要使用我们覆写的方法;
但是由于我们调用的父类中未被覆写的fatherShowDisplay方法调用了父类的display方法,所以导致程序调用的时候调用了父类的display方法!
通俗说法①:我们国家数据局早已经更新【覆写】了国民经济指数,但是你局里员工【内部其他方法】给外人调数据的时候还是调用的以前的老旧数据!!!这样不太合适吧!
②使用虚函数的情况,再来看看输出结果
#include<iostream>
using namespace std;
class Father //基类 Father
{
public:
virtual void display() {cout<<"Father::display()\n";}
//在函数中调用了,子类覆盖基类的函数display()
void fatherShowDisplay() {display();}
}; class Son:public Father //子类Son
{
public:
//重写基类中的display()函数
void display() {cout<<"Son::display()\n";}
}; int main()
{
Son son; //子类对象
son.fatherShowDisplay(); //通过基类中未被覆盖的函数,想调用子类中覆盖的display函数
}
输出结果为:Son::display()
输出结果是我们期望的结果。
③先不查资料,自己在Java中实现上面①中的函数看看输出结果
class Father{
public void display(){
System.out.println("父类显示000000000");
}
public void fatherShowDisplay(){
display();
}
} class Son extends Father{
@Override/
public void display() {
System.out.println("子类显示111111111");
}
} public class Client {
public static void main(String[] args) {
Father father=new Father();
Son son=new Son(); father.fatherShowDisplay();
son.fatherShowDisplay();
}
}
显示结果【Java没有出现C++中遇到的相关问题!】:
父类显示000000000
子类显示111111111
(2)在使用指向子类对象的基类指针,并调用子类中的覆盖函数时,如果该函数不是虚函数,那么将调用基类中的该函数;如果该函数是虚函数,则会调用子类中的该函数。
①有使用虚函数的例子
#include<iostream>
using namespace std;
class Father //基类 Father
{
public:
void display()
{cout<<"Father::display()\n";}
}; class Son:public Father //子类Son
{
public:
void display() //覆盖基类中的display函数
{cout<<"Son::display()\n";}
}; int main()
{
Father *fp; //定义基类指针
Son son; //子类对象
fp=&son; //使基类指针指向子类对象
fp->display(); //通过基类指针想调用子类中覆盖的display函数
}
输出结果:Father::display()
果然是调用了父类中的原始方法,没有调用子类覆写的方法
②使用虚函数的例子
#include<iostream>
using namespace std;
class Father //基类 Father
{
public:
void virtual display() //定义了虚函数
{cout<<"Father::display()\n";}
}; class Son:public Father //子类Son
{
public:
void display() //覆盖基类中的display函数
{cout<<"Son::display()\n";}
}; int main()
{
Father *fp; //定义基类指针
Son son; //子类对象
fp=&son; //使基类指针指向子类对象
fp->display(); //通过基类指针想调用子类中覆盖的display函数
}
使用虚函数的输出结果:Son::display()
确实调用的子类覆写方法
通俗说法②:现在一名将军【本质上也是士兵】-用手指指着【指针】-士兵【实例化对象】的询问名字【调用方法】,一对父子也在军队中服役,当询问老父亲【父类对象】的名字的时候,父亲向将军报上自己的名字;当询问儿子【子类对象】的名字时,他竟然报了他爹的名字!!!
③Java中的例子【Java对象引用-C++指针】
class Father{
public void display(){
System.out.println("父类显示000000000");
}
public void fatherShowDisplay(){
display();
}
} class Son extends Father {
@Override
public void display() {
System.out.println("子类显示111111111");
}
} public class Client {
public static void main(String[] args) {
// Father son=new Son();//这种和下面的其实是一样的,【对象向上转型】 Father father=new Father();
father.fatherShowDisplay(); father=new Son();
father.fatherShowDisplay(); }
}
程序输出:
父类显示000000000
子类显示111111111
这种情况下,Java依然没有C++虚函数那样的问题!!!
3、实际意义
通过2-主要作用,他解决的问题知道:虚函数是为了解决子类覆写方法的一致性,一旦覆写后续调用全部都使用最新的方法,不出现调用以前方法的情况!对比一下Java语言中的方法覆写!
虚函数就是为了解决编程中的多态特性吗!
4,实现原理
小知识:
编译程序在编译阶段并不能确切知道将要调用的函数,只有在程序运行时才能确定将要调用的函数,为此要确切知道该调用的函数,要求联编工作要在程序运行时进行,这种在程序运行时进行联编工作被称为动态联编。
动态联编必须包括以下方面:
(1)成员函数必须声明为virtual
(2)如果基类中声明了为虚函数,则派生类中不必再声明。
调用方式:
通过对象的指针或引用调用成员函数;或通过成员函数调用,反之就无法实现动态联编。
5,Java中是否存在虚函数???
首先声明,Java中没有虚函数这个概念、也不存在C++虚函数这样的问题,原因:Java本身【面向对象都有】的三大特性中就有多态这个特性。
Java的普通函数就相当于C++的虚函数,动态绑定是Java的默认行为【核心:Java没有虚函数的本质原因所在】。
6,Java实现C++遇到的问题
代码如下:
class Father{
private void display(){//私有化该方法,子类就不能覆写该方法
System.out.println("父类显示000000000");
}
public void fatherShowDisplay(){
display();
}
} class Son extends Father{
public void display() {//这里不是覆写父类方法,而是创建了一个全新的方法
System.out.println("子类显示111111111");
}
} public class Client {
public static void main(String[] args) {
Father father=new Father();
Son son=new Son();
Father fs=new Son();//向上转型 father.fatherShowDisplay();
son.fatherShowDisplay();
son.display(); fs.fatherShowDisplay();
((Son)fs).display();//【强制】向下转型
}
}
数据输出:
父类显示000000000
父类显示000000000
子类显示111111111
父类显示000000000
子类显示111111111
这里的方法已经不是覆写了,而是父类的方法被私有化,子类是相当于新建了一个方法。
7,参考链接
https://www.jianshu.com/p/d07e0ac0ba3c?from=singlemessage
https://blog.csdn.net/trojanpizza/article/details/6556604
C++虚函数【Java有虚函数吗?】的更多相关文章
- 关于C++与Java中虚函数问题的读书笔记
之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...
- TWinControl与TControl的覆盖函数(TWinControl对TControl的10个消息覆盖函数,17个覆盖函数,私有虚函数仍可多态)
手工找出来,对比一下,有助于VCL框架的理解.----------------------------------------------------------------------------- ...
- C++学习笔记(十二):类继承、虚函数、纯虚函数、抽象类和嵌套类
类继承 在C++类继承中,一个派生类可以从一个基类派生,也可以从多个基类派生. 从一个基类派生的继承称为单继承:从多个基类派生的继承称为多继承. //单继承的定义 class B:public A { ...
- C++ 虚函数 、纯虚函数、接口的实用方法和意义
也许之前我很少写代码,更很少写面向对象的代码,即使有写多半也很容易写回到面向过程的老路上去.在写面向过程的代码的时候,根本不管什么函数重载和覆盖,想到要什么功能就变得法子的换个函数名字,心里想想:反正 ...
- 【转】C++ 虚函数&纯虚函数&抽象类&接口&虚基类
1. 动态多态 在面向对象语言中,接口的多种不同实现方式即为多态.多态是指,用父类的指针指向子类的实例(对象),然后通过父类的指针调用实际子类的成员函数. 多态性就是允许将子类类型的指针赋值给父类类型 ...
- C++ 虚函数&纯虚函数&抽象类&接口&虚基类(转)
http://www.cnblogs.com/fly1988happy/archive/2012/09/25/2701237.html 1. 多态 在面向对象语言中,接口的多种不同实现方式即为多态.多 ...
- 【C++】多态性(函数重载与虚函数)
多态性就是同一符号或名字在不同情况下具有不同解释的现象.多态性有两种表现形式: 编译时多态性:同一对象收到相同的消息却产生不同的函数调用,一般通过函数重载来实现,在编译时就实现了绑定,属于静态绑定. ...
- c++ 虚函数和纯虚函数
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象 ...
- C++ - 虚基类、虚函数与纯虚函数
虚基类 在说明其作用前先看一段代码 class A{public: int iValue;}; class B:public A{public: void bPrintf(){ ...
随机推荐
- 002-创建型-03-单例模式(Singleton)【7种】、spring单例及原理
一.概述 保证一个类仅有一个实例,并提供一个全局访问点 私有构造器.线程安全.延迟加载.序列化和反序列化安全.反射攻击 1.1.适用场景 1.在多个线程之间,比如servlet环境,共享同一个资源或者 ...
- 002-创建型-01-工厂方法模式(Factory Method)
一.概述 定义一个创建对象的接口,但让实现这个接口的类来决定实例化那个类,工厂方法让类的实例化推迟到子类中进行. 工厂方法模式(FACTORY METHOD)同样属于一种常用的对象创建型设计模式,又称 ...
- 阶段5 3.微服务项目【学成在线】_day18 用户授权_11-前端集成认证授权-身份校验
把下面赋值到nginx中 前端的服务需要配置一下 重启nginx 启动教学管理的前端 没有登陆直接就进来教学管理的后端了 下面我们要做的就是这两件事 1.前端页面校验用户的身份,如果用户没有登录则跳转 ...
- C# winform中使用Panel调节窗口变化是各控件的位置(转)
我的目的是在窗口上有些控件,在窗口大小变化时,上面的控件位置不动,大小也不动.下面的控件随着窗口的大小变化而变大. 做法是用两个panel,panelTop和panelFill.上面的控件都放到pan ...
- (十二)class文件结构:魔数和版本
一.java体系结构 二.class格式文件概述 class文件是一种8位字节的二进制流文件, 各个数据项按顺序紧密的从前向后排列, 相邻的项之间没有间隙, 这样可以使得class文件非常紧凑, 体积 ...
- Django文档
https://docs.djangoproject.com/zh-hans/2.1/
- 表格组件---bootstrapTable
bootstrapTable中文官方网站http://bootstrap-table.wenzhixin.net.cn1.文件引用 //1.引用Jquery <script src=" ...
- pip3快速下载paddle
安装百度的paddle paddle时很慢,后来采用国内的源,速度嗖嗖滴 pip3 install -U paddlepaddle -i https://pypi.douban.com/simple/ ...
- 白嫖百度 Tesla V100 笔记(在 AI Studio 上使用 tensorflow 和 pytorch 的方法)
登陆百度 AI Studio 并按照教程创建新项目 启动项目并进入控制台 下载 Anaconda3/Miniconda3 安装脚本 安装在 ~/work/*conda3 目录 输入命令 source ...
- 【ARM-Linux开发】TI 关于Gstreamer使用的几个参考
http://processors.wiki.ti.com/index.php/Example_GStreamer_Pipelines#H.264_RTP_Streaming http://proce ...