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; 第二种使用工具…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
关于 WASM:1. WASM 基础原理
一、WASM 简介 1.1 WebAssembly 是什么? WebAssembly(WASM) 是一种能在现代浏览器中高效运行的二进制指令格式,它不是传统的编程语言,而是一种 低级字节码格式,可由高级语言(如 C、C、Rust&am…...
JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作
一、上下文切换 即使单核CPU也可以进行多线程执行代码,CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短,所以CPU会不断地切换线程执行,从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...
C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...
