​C++中虚函数 纯虚函数 虚基类的基础知识点​

news2024/11/21 11:03:57

一、前言

     原文转载自 c++中的 虚函数 纯虚函数 虚基类_名字全都被占用了的博客-CSDN博客,为了理解下C++中虚函数 纯虚函数 虚基类的基础知识点。

二、虚函数 纯虚函数 虚基类三者区别      

    1.虚函数是用于多态中virtual修饰父类函数,确保父类指针调用子类对象时,运行子类函数的。

    2.纯虚函数是用来定义接口的,也就是基类中定义一个纯虚函数,基类不用实现,让子类来实现。

    3.虚基类是用来在多继承中,如果父类继承自同一个父类,就只实例化一个父类(说的有点绕,就是只实例化一个爷爷的意思)

2.1、虚函数

    这个和多态有关,多态的定义不清楚的话到其他地方先了解一下,多态的三个必要条件:1.继承 2.重载 3.父类指针指向子类对象。

看一下程序

第一个是没有使用virtual的,没有使用多态的:

 
  1. class A

  2. {

  3. public:

  4. void printf(){

  5. cout<<"printf A"<<endl;

  6. }

  7. };

  8. class B : public A

  9. {

  10. public:

  11. void printf(){

  12. cout<<"printf B"<<endl;

  13. }

  14. };

  15. int main(int argc, const char * argv[])

  16. {

  17. A *a = new A();

  18. a->printf();

  19. B *b = new B();

  20. b->printf();

  21. return 0;

  22. }

结果:

printf A

printf B

这是最基本的用法,没有多态,只有继承,下面是使用了多态但是没有引用virtual关键字的情况,多态的作用请参考其他地方的文章:

 
  1. int main(int argc, const char * argv[])

  2. {

  3. A *a = new B();

  4. a->printf();

  5. return 0;

  6. }

结果:

printf A

因为类的定义都一样,所以就没再写出来了,当父类指针指向子类对象的时候,如果不使用virtual,父类调用方法的时候还是调用了父类自己的方法,没有调用子类重写的方法,所以就没有实现到多态的作用,我们再来在父类中试试加入virtual关键字看看:

 
  1. class A

  2. {

  3. public:

  4. virtual void printf(){

  5. cout<<"printf A"<<endl;

  6. }

  7. };

  8. class B : public A

  9. {

  10. public:

  11. void printf(){

  12. cout<<"printf B"<<endl;

  13. }

  14. };

  15. int main(int argc, const char * argv[])

  16. {

  17. A *a = new B();

  18. a->printf();

  19. return 0;

  20. }

结果

printf B

     virtual是加入到父类中的,子类的代码没改变,main函数还是父类指针指向子类对象,结果终于可以打印到子类重写的方法了,所以证实了虚函数是用于多态中virtual修饰父类该重写的函数,确保父类指针调用子类对象时运行子类函数的。

2.2 、纯虚函数

    纯虚函数就像java的接口,使用了纯虚函数的类不能被实例化,定义了纯虚函数的类不用写纯虚函数的实现,由子类实现,下面看代码:

 
  1. class A

  2. {

  3. public:

  4. virtual void printf() =0;

  5. };

  6. void A::printf()//纯虚函数可以不写实现

  7. {

  8. cout<<"printf A"<<endl;

  9. }

  10. class B : public A

  11. {

  12. public:

  13. void printf(){

  14. cout<<"printf B"<<endl;

  15. }

  16. };

  17. int main(int argc, const char * argv[])

  18. {

  19. A *a =new A();//编译出错,纯虚函数的类不能实例化

  20. a->printf();

  21. return 0;

  22. }

virtual void printf() = 0;这是虚函数的写法,我在下面写了虚函数的实现 void A::printf(),其实写不写都没关系,写了也起不了作用= 。= 。然后我才main函数中尝试吧纯虚函数的类实例化,结果直接报错,说明纯虚函数是不能实例化的。

 
  1. int main(int argc, const char * argv[])

  2. {

  3. A *a =newB();//这里使用了多态

  4. a->printf();

  5. return 0;

  6. }

结果:

printf B

把main函数的a指向了子类的对象,结果可以正确打印出子类的方法。由此说明了纯虚函数也是为多态服务的,它的作用是定义一个接口,让子类去实现。

2.3、虚基类

虚基类是c++独有的东西,因为c++中有多继承,也是关键字virtual相关的定义。

先来说说多继承,如果爷爷类(暂把父类的父类暂定为爷爷类= = ),父类继承自爷爷类。如果孙类继承自多个父类(听起来有点怪异),那么如果不使用虚基类,就会实例化多个爷爷类对象(越说越离奇),编译器会报错,说有歧义性。如果父类继承自虚基类,则可以解决多个父类不会实例化多个爷爷的问题,就是只有一个爷爷。

 
  1. class Grandfather{

  2. public:

  3. int flag;

  4. Grandfather(){

  5. flag = 1;

  6. }

  7. };

  8. class Father1:publicGrandfather{

  9. public:

  10. Father1(){

  11. flag = 2;

  12. }

  13. };

  14. class Father2:publicGrandfather{

  15. public:

  16. Father2(){

  17. flag = 3;

  18. }

  19. };

  20. class Son:public Father1,publicFather2{

  21. };

  22. int main(int argc, const char * argv[])

  23. {

  24. Son *son = new Son();

  25. cout<<son->flag<<endl;//这里编译错误,没法指定flag是指定那一个,歧义

  26. return 0;

  27. }

如果没有使用虚基类,多个父类继承自同一个爷爷类,就会产生歧义,到底是不是同一个爷爷?如果父类继承虚基类就不同了:

 
  1. class Grandfather{

  2. public:

  3. int flag;

  4. Grandfather(){

  5. flag = 1;

  6. cout<<"Grandfather flag = "<<flag <<endl;

  7. }

  8. };

  9. class Father1:virtualpublicGrandfather{

  10. public:

  11. Father1(){

  12. flag = 2;

  13. cout<<"Father1 flag = "<<flag<<endl;

  14. }

  15. };

  16. class Father2:virtualpublicGrandfather{

  17. public:

  18. Father2(){

  19. flag = 3;

  20. cout<<"Father2 flag = "<<flag<<endl;

  21. }

  22. };

  23. class Son:public Father1,publicFather2{

  24. };

  25. int main(int argc, const char * argv[])

  26. {

  27. Son *son = new Son();

  28. cout<<son->flag<<endl;

  29. return 0;

  30. }

结果:

Grandfather flag = 1

Father1 flag = 2

Father2 flag = 3

3

现在,可以运行了,class Father2:virtual public Grandfather,就是继承虚基类的写法,爷爷对象只有一个,爷爷类的变量也只实例化了一次,那为什么最后打印出来的是3呢?看构造函数的顺序就可以看出来了,现在构造了爷爷类,再构造第一个继承的父类,最后继承第二个继承的父类,因此flag最后保持在第二个父类的修改值里了。

总的来说,虚函数 ,纯虚函数是为了多态服务,虚基类是为了只实例化一次基类存在的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/550384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven基础学习---4、Maven的使用(IDEA)

1、创建父工程&#xff08;本人用的是IDEA2022.3&#xff09; 1、创建Project 2、配置Maven信息 如果没有提前设置过Setting for new project这个配置&#xff0c;那么每次创建Project后都需要设置Maven家目录位置&#xff0c;否则IDEA将使用内置的Maven核心程序&#xff08;…

数据仓库理论

数据仓库理论 基础理论数据仓库主要特征面相主题集成性非易失性、非易变性时变性 OLTP、OLAPOLTPOLAP对比 数据库与数据仓库的区别数据仓库、数据集市数据仓库分层架构分层思想和标准阿里巴巴数仓三层架构ODS层DW层DA层&#xff08;ADS层&#xff09; 分层的好处好处 ETL和ELT的…

mysql存储过程实例统计最大销售数量

1.需求 统计某天的销售的商品中&#xff0c;数量大于m的最大的销售数量。 传入参数&#xff1a;销售日期&#xff0c;销售数量 返回参数&#xff1a;最大销售数量 2.数据库表 销售表 CREATE TABLE t_sale ( id int NOT NULL COMMENT ‘主键’, good_id int NULL COMMENT ‘…

[山海关crypto 训练营 day17]

[HNCTF 2022 WEEK3]pnearq 题目代码和数据 from Crypto.Util.number import * from gmpy2 import next_prime from flag import flagp getPrime(1024) q next_prime(p) n p*q e 0x10001 c pow(bytes_to_long(flag), e, n) print(f"n {n}") print(f"c {…

chatgpt赋能Python-python8_9

Python 8-9: 了解更多关于Python的新特性 Python 作为一种高级编程语言已经被广泛应用于数据科学&#xff0c;Web开发&#xff0c;人工智能等领域。Python 8-9带来了新特色的更新和改进&#xff0c;这些功能使得Python更加强大和易于使用&#xff0c;吸引了越来越多开发者的关…

符尧最新研究:大语言模型玩砍价游戏?技巧水涨船高!

深度学习自然语言处理 原创作者&#xff1a;鸽鸽 若干年前&#xff0c;AlphaGo Zero用两个AI代理切磋围棋技艺&#xff0c;打败了人类。今早&#xff0c;符尧的一篇论文刷新了我的认知&#xff1a;让大语言模型相互对弈&#xff0c;再加一个评论家提供建设性意见&#xff0c;提…

自动控制原理备考-1题-传递函数

首先致敬西北工业大学自动控制原理的无冕之王张科老师。 期末考试&#xff0c;先下手为强&#xff0c;后下手遭殃。今天我们就开始一起针对期末考试有关题型一一梳理&#xff0c;突破解决。 给你一个系统结构图&#xff0c;让你求R&#xff08;s)和N(s)同时作用下的C(s)。基本…

机器学习项目实战-能源利用率 Part-5(模型解释)

博主前期相关的博客可见下&#xff1a; 机器学习项目实战-能源利用率 Part-1&#xff08;数据清洗&#xff09; 机器学习项目实战-能源利用率 Part-2&#xff08;探索性数据分析&#xff09; 机器学习项目实战-能源利用率 Part-3&#xff08;特征工程与特征筛选&#xff09; 机…

匿名通信 Windows 客户端的设计与实现

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 本课题基于 U-TRI 匿名通信系统&#xff0c;设计一个 Windows 匿名通信客户端。该客户端在匿名通信系统中扮演了重要角色&#xff0c;实现了两个重要功能&#xff1a;第一&#xff0c;实现匿名通信协议&#xff0c;拦截/修改主…

TCP 三次握手与四次挥手

1 三次握手 三次握手的过程如下图&#xff1a; 一开始&#xff0c;客户端和服务端都处于 CLOSE 状态。先是服务端主动监听某个端口&#xff0c;处于 LISTEN 状态 客户端会随机初始化序号&#xff08;client_isn&#xff09;&#xff0c;将此序号置于 TCP 首部的「序号」字段中…

如何在 iPhone 上恢复已删除的应用程序数据

您是不小心删除了重要应用程序并且似乎无法在您的设备上找到它的 iPhone 用户吗&#xff1f;别担心&#xff0c;你并不孤单。在 iPhone 上丢失应用程序可能会令人沮丧&#xff0c;但幸运的是&#xff0c;有一些方法可以恢复它们。在本文中&#xff0c;我们将通过分步说明向您展…

你真的懂Java中的Cloneable接口和深拷贝么?

Cloneable接口 和 深拷贝 &#x1f490;文章导读 这篇文章就为大家讲讲什么是Cloneable接口&#xff0c;接口的用法以及什么是深拷贝和浅拷贝&#xff0c;如果有不足的地方&#xff0c;还望读者在评论区提出&#xff01;&#xff01;&#xff01; 上篇文章讲过用Comparable接口…

单模光纤的特征方程以及MATLAB求解

在之前的文章中&#xff0c;我们写出了单模光纤的特征方程以及对应的导波模式 这里我们在MATLAB中求解特征方程并表示出几个归一化参数的变化曲线 用到的公式是单模光纤导波模式的特征方程&#xff1a; clear close all tic Vmax 10; N 100;for j 1:NV(j) j/N*Vmax;Vtemp …

电脑微信占用100多GB空间 解决办法来了:重回清爽流畅

这几天微信吃内存的话题又上热搜了&#xff0c;作为一款10亿用户的国民级APP&#xff0c;微信的真是让人又爱又恨&#xff0c;不用几乎不可能&#xff0c;用起来槽点又多&#xff0c;光是磁盘占用就是个头疼的问题。 不论是工作还是日常沟通&#xff0c;微信里面的文件及语音、…

python中的类型转换

文章目录 类型转换简介int()float()str()bool() 类型转换简介 所谓的类型转换&#xff0c;将一个类型的对象转换为其他对象。 类型转换不是改变对象本身的类型&#xff0c;而是将对象的值转换为新的对象。 类型转换四个函数 int() 、 float() 、 str() 、 bool() int() int()…

cpp11实现线程池(一)——项目介绍

项目介绍 线程池是库的形式提供给用户&#xff0c;是必须放到代码中&#xff0c;不能单独运行&#xff0c;亦称为基础组件 第一版线程池任务对象使用继承技术&#xff0c;提供一个抽象基类Task&#xff0c;里面有一个纯虚函数run()&#xff0c;使用时继承该类&#xff0c;并重…

第二篇:强化学习中的7个基础概念

你好&#xff0c;我是zhenguo&#xff08;郭震&#xff09; 这是强化学习第二篇&#xff1a;强化学习7个基础概念 在强化学习中&#xff0c;智能体需要在不断尝试和错误的过程中学习&#xff0c;通过观察环境的反馈&#xff08;奖励或惩罚&#xff09;来调整自己的行为&#xf…

windows系统安装curl

下载安装包 https://curl.se/windows/ 2.如图所示&#xff0c;把下载的zip包解压到C盘某个目录下 把bin目录配置到系统环境变量Path里 在命令行里直接输入curl即可开始使用 5.curl测试访问百度 6.curl 测试ip端口连通性 用法&#xff1a;curl -v ip:port

推荐一款C端的低代码产品

目录 写在前面 低代码平台 平台怎么选 各平台区别 为什么选它 写在前面 大家都知道低代码这个叫法是从B端叫起来的&#xff0c;也就是说不管是业务人员还是开发人员&#xff0c;都是企业内部使用。那么有没有C端的&#xff0c;且免费使用的低代码产品呢&#xff1f; 低代码…

Matlab论文插图绘制模板第93期—带类别标签的散点图

在之前的文章中&#xff0c;分享了很多Matlab散点图的绘制模板&#xff1a; 进一步&#xff0c;再来分享一种特殊的散点图&#xff1a;带类别标签的散点图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请…