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

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设计模式的传统实现手法。
http://www.lryc.cn/news/68922.html

相关文章:

  • Akura Medica:新型静脉血栓切除系统,完成首次人体试验
  • 大型央企集团财务经营分析框架系列(三)
  • C++并发编程:std::future、std::async、std::packaged_task与std::promise的深度探索
  • 测牛学堂:2023软件测试学习教程之sql的单表查询排序和模糊查询
  • CSS第一天总结
  • js中各种console使用方法大全
  • 江西棒球未来发展规划·棒球1号位
  • 【笔记】做二休五
  • Qt6之字符串类内存分配新变化——16的次方增加
  • C++ 名称空间
  • 作为一名普通的java程序员,我想和大家分享一下4年来的工作内容
  • CyberLink的专业视频编辑软件ActionDirector Ultra 3.0版本在win10系统的下载与安装配置教程
  • 在外远程访问公司局域网用友畅捷通T财务软件 - 远程办公
  • VariantAutoencoder(VAE)中使用生成好的模型进行声音生成
  • C++数据封装以及定义结构的详细讲解鸭~
  • MySql 数据库的锁机制和原理
  • try catch finally 里面有return的执行顺序
  • 美团前高级测试工程师教你如何使用web自动化测试
  • MySql.Data.dll 因版本问题造成报错的处理
  • 囚徒困境——从博弈论的角度解释“美女配丑男”
  • 运算符重载函数作为类的成员函数——有理数的约分
  • mysql数据库的内置函数--7
  • DS3800HPIB 有效执行任务的所有程序
  • 图像比对、人像比对和人脸识别的区别是什么?
  • python中的抽象基类
  • 耗时几个月,终于决定把原本想用于商业的系统开源了
  • HarmonyOS应用端云一体化开发主要流程
  • NoSQL之 Redis配置与优化
  • Redis哨兵模式
  • 数据库管理-第七十六期 如何升级19c RAC(20230516)