effective c++ 35 考虑virtual函数以外的其他选择
effective c++ 35 考虑virtual函数以外的其他选择
在本节中,作者给出了一些可以替代调用virtual函数的方法。下面就一一进行介绍。
分析
1.考虑NVI的实现方式(模板方法设计模式)
父类和子类都调用healthValue同一接口,但是返回值不同。这是一种public非virtual函数调用virtual函数的实现多态的方法。
#include <iostream>class GameCharacter
{
public:// derived classes do not redefine thisint healthValue() const{int retVal = doHealthValue();return retVal;}private:// derived classes may redefine this// default algorithm for calc healthvirtual int doHealthValue() const{return 0;}
};class MyCoolCharacter : public GameCharacter
{
private:int doHealthValue() const{return 17;}
};class MyRichCharacter : public GameCharacter
{
private:int doHealthValue() const{return 100;}
};int main()
{GameCharacter* gameCharacter = new MyCoolCharacter();std::cout << gameCharacter->healthValue() << std::endl; GameCharacter* gameCharacter2 = new MyRichCharacter();std::cout << gameCharacter2->healthValue() << std::endl;
}
have a try
2.考虑函数指针(策略模式)去实现多态
父类和子类都调用healthValue方法,但是二者的返回值是不同的。这里是因为healthValue方法内调用了healthFunc指针所指向的方法,但是父类和子类中healthFunc指针所指向的方法是不同的,通过这样的方式实现了多态。
// The Strategy Pattern via Function Pointers.#include <iostream>class GameCharacter;// Function for the default health calculation algorithm.
int defaultHealthCalc(const GameCharacter& gc)
{std::cout << "defaultHealthCalc" << std::endl;return 0;
}int lossHealthFastCalc(const GameCharacter& gc)
{std::cout << "lossHealthFastCalc" << std::endl;return 0;
}int lossHealthSlowCalc(const GameCharacter& gc)
{std::cout << "lossHealthSlowCalc" << std::endl;return 0;
}class GameCharacter
{
public:typedef int (*HealthCalcFunc)(const GameCharacter&);explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) :healthFunc(hcf){}int healthValue() const{return healthFunc(*this);}private:HealthCalcFunc healthFunc;
};class EvilBadGuy : public GameCharacter
{
public:explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc) :GameCharacter(hcf){}
};class GoodGuy : public GameCharacter
{
public:explicit GoodGuy(HealthCalcFunc hcf = defaultHealthCalc) :GameCharacter(hcf){}
};int main()
{GameCharacter* gameCharacter = new EvilBadGuy(lossHealthFastCalc);gameCharacter->healthValue();GameCharacter* gameCharacter2 = new GoodGuy(lossHealthSlowCalc); gameCharacter2->healthValue();
}
have a try
3.考虑使用std::function(策略模式)
本例和第二点的例子并不大的区别,只是使用了std::function充当函数指针。std::function可以接受更多类型的可调用对象,例如lambda function, 类的成员函数,仿函数等等。
#include <functional>
#include <iostream>// Forward declaration
class GameCharacter;// Function for the default health calculation algorithm.
int defaultHealthCalc(const GameCharacter& gc)
{std::cout << "defaultHealthCalc" << std::endl;return 0;
}class GameCharacter
{
public:// HealthCalcFunc is any callable entity that can be called with// anything compatible with a GameCharacter and that returns// anything compatible with an int; see below for details.typedef std::function<int (const GameCharacter&)> HealthCalcFunc;explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) :healthFunc(hcf){}int healthValue() const{return healthFunc(*this);}private:HealthCalcFunc healthFunc;
};class EvilBadGuy : public GameCharacter
{
public:explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc) :GameCharacter(hcf){}
};class EyeCandyGuy : public GameCharacter
{
public:explicit EyeCandyGuy(HealthCalcFunc hcf = defaultHealthCalc) :GameCharacter(hcf){}
};// New flexibility:// Health calculation function.
// Note: non-int return type.
short calcHealth(const GameCharacter&)
{std::cout << "calcHealth" << std::endl;return 256;
}// Class for health calculation object.
struct HealthCalculator
{// Calculation function object.int operator()(const GameCharacter&) const{std::cout << "HealthCalculator operator()" << std::endl;return 7;}
};class GameLevel
{
public:// Health calculation member function.// Note: non-int return type.float health(const GameCharacter&) const{std::cout << "GameLevel health" << std::endl; return 7.5f;}
};int main()
{GameCharacter* gameCharacter = new EvilBadGuy(calcHealth);gameCharacter->healthValue();GameCharacter* gameCharacter2 = new EvilBadGuy(HealthCalculator());gameCharacter2->healthValue();GameLevel gameLevel;GameCharacter* gameCharacter3 = new EvilBadGuy(std::bind(&GameLevel::health, gameLevel, std::placeholders::_1));gameCharacter3->healthValue();
}
have a try
4.经典的策略模式
经典的策略模式是将继承体系内的virtual函数替换为另一个继承体系内的virtual函数。
// The "Classic" Strategy Pattern.#include <iostream>class GameCharacter;class HealthCalcFunc
{
public:virtual int calc(const GameCharacter& gc) const{std::cout << "HealthCalcFunc calc" << std::endl;return 17;}
};class MyHealthCalcFunc : public HealthCalcFunc
{
public:int calc(const GameCharacter& gc) const{std::cout << "MyHealthCalcFunc calc" << std::endl;return 25;}
};HealthCalcFunc defaultHealthCalcFunc;class GameCharacter
{
public:explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalcFunc) :pHealthCalcFunc(phcf){}int healthValue() const{return pHealthCalcFunc->calc(*this);}private:HealthCalcFunc* pHealthCalcFunc;
};class EvilBadGuy : public GameCharacter
{
public:explicit EvilBadGuy(HealthCalcFunc* phcf = &defaultHealthCalcFunc) :GameCharacter(phcf){}
};int main()
{MyHealthCalcFunc myHealthCalcFunc;GameCharacter* gameCharacter = new EvilBadGuy(&myHealthCalcFunc);gameCharacter->healthValue();}
have a try
总结
- 使用non-virtual interface(NVI)手法, 那么是Template Method设计模式的一种特殊形式。它以public non-virtual成员函数包裹较低访问性的virtual函数。
- 将virtual函数替换为"函数指针成员变量", 这是Strategy设计模式的一种分解表现形式。
- 使用std::function成员变量替换virtual函数,因而允许任何可调用对象搭配一个兼容于需求的签名式。这也是Strategy设计模式的某种形式。
- 将继承体系内的virtual函数替换为另一个继承体系内的virtual函数。这是Strategy设计模式的传统实现手法。
相关文章:
effective c++ 35 考虑virtual函数以外的其他选择
effective c 35 考虑virtual函数以外的其他选择 在本节中,作者给出了一些可以替代调用virtual函数的方法。下面就一一进行介绍。 分析 1.考虑NVI的实现方式(模板方法设计模式) 父类和子类都调用healthValue同一接口,但是返回值不同。这是一种public非…...
Akura Medica:新型静脉血栓切除系统,完成首次人体试验
Akura Medical公司宣布,其机械血栓切除平台在人体首次使用成功,这是一项具有突破性的技术,可以有效地治疗肺栓塞、深静脉血栓等血栓栓塞疾病。该平台使用了一种与众不同的方法,可以高效地清除血管内的血栓,同时保护血管…...
大型央企集团财务经营分析框架系列(三)
01集团经营管理分析的切入点 集团经营管理分析的切入点往往是从财务分析开始。 往往在一家企业里面,财务方面的信息化建设是要早于其它方面的信息化建设的,业务标准化程度比较高,数据标准化程度也比较高,分析框架也相对成熟。 …...
C++并发编程:std::future、std::async、std::packaged_task与std::promise的深度探索
C并发编程:std::future、std::async、std::packaged_task与std::promise的深度探索 一、引言 (Introduction)1.1 并发编程的概念 (Concept of Concurrent Programming)1.2 C并发编程的重要性 (Importance of Concurrent Programming in C)1.3 关于std::future、std:…...
测牛学堂:2023软件测试学习教程之sql的单表查询排序和模糊查询
单表查询的排序 关键字:order by 排序的类型,升序字段:ASC ,省略的话默认就是升序。 降序的字段:DESC 语法: order by 字段名 ASC| DESC返回的表则会按照给定的字段排序 例子:查询学生的考试成…...
CSS第一天总结
css第一天总结 css简介 CSS 是层叠样式表 ( Cascading Style Sheets ) 的简称. 有时我们也会称之为 CSS 样式表或级联样式表。 CSS 是也是一种标记语言 CSS 主要用于设置 HTML 页面中的文本内容(字体、大小、对齐方式等)、图片的外形(宽高、…...
js中各种console使用方法大全
console 1.console.log() (1)用于标准输出流的输出,也就是在控制台中显示一行信息。 (2)当传递多个参数时,控制台输出时将以空格分隔这些参数。 (3)也可以用占位符来定义输出的格…...
江西棒球未来发展规划·棒球1号位
关于江西棒球未来发展规划: 一、总体思路 江西棒球运动要立足当前,着眼长远,切实增强鼓励支持体育运动的社会氛围,弘扬体育精神,深化体育改革,加强体育基层建设,努力建设中国棒球之乡。把打造品牌赛事和培养明星运动员作为两手抓的发展方向,不断增强江西棒球运动的整体实力和…...
【笔记】做二休五
在记录去超市购物,菜场买菜,社区团购的花费时,将每个物品的价格记录下来。 大家应该善加利用自己所拥有的事物,若勉强想要利用自己没有的,只会让自己痛苦。 打扫&洗衣服 小苏打是可用于家庭清洁的万能清洁剂&…...
Qt6之字符串类内存分配新变化——16的次方增加
qt提供了比标准c string更强大,更丰富,更实用的字符串类QString,它的主要功能22个已经在之前逐一分析过,感兴趣的可前往以下链接查看,本文主要重点分析下qt在字符串类上面做的优化,主要是两个方面ÿ…...
C++ 名称空间
一、名称空间 1.1、引入名称空间的背景 在C中的名称可以是变量,函数,类以及类的成员。随着项目的增大,名称相互冲突的可能性也在增大。使用多个厂商的类库时,可能导致名称冲突。例如,两个库都定义了名为Listÿ…...
作为一名普通的java程序员,我想和大家分享一下4年来的工作内容
一直有小伙伴想了解更多关于我的工作内容,所以今天我来分享一下我作为一名普通java程序员,4年来工作内容发生了哪些变化,以及我有什么感悟。 我是16届毕业生,我的第一份工作是做外包,第一年的时间里测试偏多ÿ…...
CyberLink的专业视频编辑软件ActionDirector Ultra 3.0版本在win10系统的下载与安装配置教程
目录 前言一、ActionDirector Ultra安装二、使用配置总结 前言 ActionDirector Ultra是CyberLink公司开发的专业视频编辑软件,旨在帮助用户创作高质量的运动和冒险视频。该工具提供了一些先进的特效和编辑工具,让用户能够轻松地剪辑、修剪、调整颜色和添…...
在外远程访问公司局域网用友畅捷通T财务软件 - 远程办公
文章目录 前言1.本地访问简介2. cpolar内网穿透3. 公网远程访问4. 固定公网地址 前言 用友畅捷通T适用于异地多组织、多机构对企业财务汇总的管理需求;全面支持企业对远程仓库、异地办事处的管理需求;全面满足企业财务业务一体化管理需求。企业一般将其…...
VariantAutoencoder(VAE)中使用生成好的模型进行声音生成
文章目录 概述一、soundgenerator.py文件soundgenerator.py实现代码一、convert_spectrogram_to_audio方法librosa.db_to_amplitudelibrosa.istft generate方法 二、generate.py文件实现代码load_fsdd函数说明select_spectrogram函数说明save_signals函数说明main函数说明 三、…...
C++数据封装以及定义结构的详细讲解鸭~
名字:阿玥的小东东 博客主页:阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 定义结构 访问结构成员 结构作为函数参数 指向结构的指针 typedef 关键字 C 数据封装 数据封装的实例 设计策略 C 类 &…...
MySql 数据库的锁机制和原理
MySQL是一种流行的关系型数据库管理系统,广泛应用于各种Web应用程序和企业级应用程序中。在MySQL中,锁是一种用于控制并发访问的机制,它可以保证数据的一致性和完整性。本文将介绍MySQL的锁机制及原理,包括锁的类型、级别和实现原…...
try catch finally 里面有return的执行顺序
目录 实例结论 实例 1.try和catch中有return时,finally里面的语句会被执行吗 我们可以来分别看看 (1)执行try中的return时 public class Solution {public static int show() {try {return 1;}finally{System.out.println("finally模块被执行");}}publi…...
美团前高级测试工程师教你如何使用web自动化测试
一、自动化测试基本介绍 1 自动化测试概述: 什么是自动化测试?一般说来所有能替代人工测试的方式都属于自动化测试,即通过工具和脚本来模拟人执行用例的过程。 2 自动化测试的作用 减少软件测试时间与成本改进软件质量 通过扩大测试覆盖率…...
MySql.Data.dll 因版本问题造成报错的处理
NetCore 链接MySQL 报 Character set ‘utf8mb3‘ is not supported by .Net Framework 异常解决_character set utf8mb3_csdn_aspnet的博客-CSDN博客 查看mysql版本号,两种办法: 第一种在数据库中执行查询:SELECT version; 第二种使用工具…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...
AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
