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

C++基础之虚函数(十七)

一.什么是多态

多态是在有继承关系的类中,调用同一个指令(函数),不同对象会有不同行为。

二.什么是虚函数

概念:首先虚函数是存在于类的成员函数中,通过virtual关键字修饰的成员函数叫虚函数。

性质:如果在基类中定义类的虚函数,那么在派生类中该函数被继承下来仍是虚函数,即使派生类中没有加virtual

重写(覆盖):派生类要保证该虚函数的名字,返回类型,参数列表都要相同。在发生重写时除了虚函数的函数体之外其他的都是在编译的时候确定的。

三.虚函数的实现机制

当基类定义了虚函数,在该类创建对象时就会在对象的存储布局的前面,新增一个虚函数指针,该指针指向虚函数表(简称虚表),在虚表中存有虚函数的入口地址。当派生类继承基类的时候,会吸收基类的成员函数(包括虚函数),那么派生类中也会有虚函数,在派生类创建对象时,也会在派生类对象的存储布局前面新增一个虚函数指针,该指针也会指向派生类自己的虚函数表,该表存有派生类虚函数的入口地址。如果派生类重写了从基类吸收的虚函数,那么就会用派生类自己的虚函数的入口地址覆盖从基类吸收过来的虚函数入口地址。

四.虚函数机制被激活的条件

  1. 基类定义虚函数
  2. 派生类重写该虚函数
  3. 创建派生类对象
  4. 基类指针指向(基类引用绑定)派生类对象
  5. 使用基类指针或引用调用派生类虚函数
#include <iostream>using std::endl;
using std::cout;class Base
{
private:int _ix;
public:Base(int x=0):_ix(x){cout<<"Base(int x=0)"<<endl;}~Base(){cout<<"~Base()"<<endl;}virtualvoid print()const{cout<<"Base::_ix = "<<_ix<<endl;}
};class Derived
:public Base
{
private:int _iy;
public:Derived(int x=0,int y=0):Base(x),_iy(y){cout<<"Derived(int x=0,int y=0)"<<endl;}~Derived(){cout<<"~Derived()"<<endl;}void print()const{cout<<"Derived::_iy = "<<_iy<<endl;}};
void func(Base* base)
{base->print();
}
void test()
{Base base(3);Derived derived(33,44);func(&base);func((Base*)&derived);func(&derived);  
}
int main()
{test();return 0;
}

 

如果不加虚函数会是什么样呢?

五.哪些函数不能设置虚函数

  1. 普通函数:包括自由函数和全局函数,虚函数必须是成员函数,而普通函数是非成员函数。
  2. 内联成员函数:内联成员函数进行函数替换是发生在编译的时候,而虚函数要实现多态要发生在运行的时候;如果将内联函数设置成虚函数就会失去内联的意义。
  3. 静态成员函数:静态成员函数发生在编译的时候,而虚函数要体现多态发生在运行的时候,静态成员函数是共享的,被该类所有对象共享没有this指针。
  4. 友元函数:如果友元函数本身是一个普通函数,那么友元函数不能被设置成虚函数。如果友元函数本身是另外一个类的成员函数,是可以被设置成虚函数的但友元关系不能被继承。
  5. 构造函数:构造函数不能被继承,但是虚函数可以被继承。

六.纯虚函数

定义形式:

virtual <返回类型> 函数名(参数列表)=0;

其中在类中声明纯虚函数,该类被称作抽象类不能创建对象只提供接口作用。纯虚函数的实现放在派生类中,如果派生类没有把基类的纯虚函数全部都实现,那么派生类也是抽象类同样不能创建对象。虽然不可以创建对象,但是抽象类可以创建抽象类的指针,因为指针相当于地址在64位系统中无论什么指针大小都是8个字节,只不过指针的指向数据的跨度不同,但是创建指针是可以的。

其中override表示重写基类的成员函数,如果没有重写就会报错。

#include <iostream>
using std::endl;
using std::cout;class Base
{
public:virtual void print() const =0;
};class Derived
:public Base
{void print() const override{cout<<"Derived::print()const"<<endl;}
};void test()
{//Base base;    errorDerived derived;Base* pbase;pbase=&derived;pbase->print();
}
int main()
{test();return 0;
}

相关文章:

  • uniapp 未配置appkey或配置错误的解决
  • vue 文件预览(docx、.xlsx、pdf)
  • 飞天使-k8s知识点28-kubernetes散装知识点5-helm安装ingress
  • 黑马鸿蒙笔记2
  • Python从零到一构建GPT模型
  • 统信 UOS V20 一键安装 Oracle 12CR2(220118)单机版
  • Android RecyclerView 滑动后选中的条目居中显示
  • 专升本-大数据
  • 创新研报 | 2024+人工智能安全报告
  • 2015年认证杯SPSSPRO杯数学建模B题(第一阶段)替换式密码全过程文档及程序
  • [深度学习]yolov8+pyqt5搭建精美界面GUI设计源码实现二
  • 农村分散式生活污水分质处理及循环利用技术指南
  • 01-机器学习概述
  • Linu修改端口号和密码
  • 【数仓】DataX软件安装及配置,从mysql同步到hdfs
  • 【Linux系统编程】快速查找errno错误码信息
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 4. 路由到控制器 - Laravel从零开始教程
  • angular组件开发
  • ECS应用管理最佳实践
  • laravel with 查询列表限制条数
  • Linux后台研发超实用命令总结
  • PHP 7 修改了什么呢 -- 2
  • Promise面试题2实现异步串行执行
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • vue从入门到进阶:计算属性computed与侦听器watch(三)
  • 分布式熔断降级平台aegis
  • 基于webpack 的 vue 多页架构
  • 前端学习笔记之观察者模式
  • 如何使用Mybatis第三方插件--PageHelper实现分页操作
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 与 ConTeXt MkIV 官方文档的接驳
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 字符串匹配基础上
  • MyCAT水平分库
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​你们这样子,耽误我的工作进度怎么办?
  • (Redis使用系列) Springboot 使用redis的List数据结构实现简单的排队功能场景 九
  • (Redis使用系列) Springboot 在redis中使用BloomFilter布隆过滤器机制 六
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)ssm捐赠救助系统 毕业设计 060945
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .net core开源商城系统源码,支持可视化布局小程序
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .net流程开发平台的一些难点(1)
  • @JSONField或@JsonProperty注解使用
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [20190416]完善shared latch测试脚本2.txt
  • [ai笔记9] openAI Sora技术文档引用文献汇总
  • [BT]小迪安全2023学习笔记(第15天:PHP开发-登录验证)
  • [BZOJ1178][Apio2009]CONVENTION会议中心