博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【C++】考虑virtual函数以外的其他选择
阅读量:6717 次
发布时间:2019-06-25

本文共 3291 字,大约阅读时间需要 10 分钟。

  假设你正在写一个视频游戏软件,游戏里有各种各样的人物,每个人物都有健康状态,而且不同的人物可能以不同的方式计算他们的健康指数.该如何设计游戏里的人物,主要如何提供一个返回人物健康指数的接口.

  方法一,基于虚函数的方法.

  在人物角色的基类增加一个成员函数heathValue,返回一个整数,表示人物的健康程度,并将声明为virtual.

1 class GameCharacter {2 public:3        virtual int healthValue() const;4        ...5 };

  heathValue声明为虚函数,因而派生类可以重新定义它,从而获得达到不同的人物可能不同的方式计算他们的健康指数的要求.

  但是没有声明为纯函数,这表示会有个计算健康指数的缺省算法.

  方法二,藉由Non-Virtual Interface手法实现Template Method模式 NVI

  该设计是令客户通过public non-virtual成员函数间接调用private virtual函数,相当对virtual函数进行一层的包装,可以称为是virtual函数的外覆器(warpper).

class GameCharacter {public:    int healthValue() const    {        ...        int retVal = doHealthValue();        ...        return retVal;    }    ...private:    virtual int doHealthValue() const    {        ...    }};

  NVI手法的一个优点可以确保在一个virtual函数被调用之前设定好适当的场景,并在调用结束之后清理场景.

  "事前工作"可以包括锁定互斥器,制造运转日志记录项,验证class约束条件,验证函数先决条件等等.

  "事后工作"可以包括互斥器解除锁定,验证函数的事后条件,再次验证class约束条件等等.

  方法三,藉由Function Pointers实现Strategy模式

  每个人物的构造函数接受一个指针,指向一个健康计算函数,调用该函数进行实际计算.

class GameCharacter;int defaultHealthCalc(const GameCharacter& gc);class GameCharacter {public:    typedef int (*HealthCalcFunc)(const GameCharacter&);    explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc):healthFunc(hcf)    {}    int healthValue() const    {        return healthFunc(*this);    }    ...private:    HealthCalcFunc healthFunc;};

  该方法的优点,同一人物类型之不同实体可以有不同的健康计算函数,只需要在构造实例时,传入不同的计算函数的指针.

  某已知人物之健康计算函数可在运动期变更,可以在GameCharacter里提供一个成员函数setHealthCalc,用来替换当前的健康指数计算函数.

  该方法的缺点,如果需要利用GameCharacter的non-public信息进行计算健康指数时,由于计算函数是non-member non-friend函数,将出现无法访问的问题.

  如果让计算函数访问成功,则需要降低GameCharacter的封装性.

  方法四,藉由tr1::function完成Strategy模式

  不再使用函数指针,而是改用一个类型为tr1::function的对象.

  可以是函数指针,函数对象,或成员函数指针,只要其签名式兼容于需求端.

View Code
class GameCharacter;int defaultHealthCalc(const GameCharacter& gc);class GameCharacter {public:    typedef    std::tr1::function
HealthCalcFunc; explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc):healthFunc(hcf) {} int healthValue() const { return healthFunc(*this); } ...private: HealthCalcFunc healthFunc;};short calcHealth(const GameCharacter&);struct HealthCalculator { int operator()(const GameCharacter&) const {...}};class GameLevel {public: float health(const GameCharacter&) const; ...};class EvilBadGuy:public GameCharacter{...};EvilBadGuy ebg1(calcHealth); //函数EvilBadGuy ebg2(HealthCalculator()); //函数对象GameLevel currentLevel;EvilBadGuy ebg3(std::tr1::bind(&GameLevel::health,currentLevel,_1); //成员函数

  优点,以tr1::function替换函数指针之后,可以允许客户在计算人物健康指数时使用任何兼容的可调用物.

  方法五,古典的Strategy模式

  将健康计算函数做成一个分离的继承体系中的virtual成员函数.

  每个GameCharacter对象都内含一个指针,指向一个来自HealthCalcFunc继承体系的对象

 

class GameCharacter;class HealthCalcFunc {public:    ...    virtual int calc(const GameCharacter& gc) const    {...}    ...};HealthCalcFunc defaultHealthCalc;class GameCharacter {public:    explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc):pHealthFunc(phcf)    {}    int healthValue() const    {        return pHealthFunc->calc(*this);    }    ...private:    HealthCalcFunc* pHealthFunc;};

  优点,只要为HealthCalcFunc继承体系添加一个派生类,就可以将一个既有的健康算法纳入使用.

  启发:针对具体的应用问题,需要认真分析其应用的特点,以及应用的后续扩展等问题,再从众多的方法,选取最合适的方法.

  不能先入为主的,随便的套用一个方法,这样可能会导致应用的后续扩展问题.总之,遇到问题,先想,再比较,最后确定方案.

  参考资料:Effective C++中文版

转载地址:http://gkumo.baihongyu.com/

你可能感兴趣的文章
魅族隔空回应雷军:开放 Flyme 对抗 MIUI
查看>>
成为阿里云大使的笔记
查看>>
《深入解析IPv6(第3版)》——2.10 参考文献
查看>>
《Adobe Illustrator CC经典教程》—第0课0.16节使用文字
查看>>
企业安全:从触觉时代到视觉时代
查看>>
Oracle Dataguard在阿里云ecs上的测试
查看>>
《Python数据科学实践指南》——0.3 为什么是Python
查看>>
《混合云计算》——2.4 检查云集成的需求
查看>>
《Axure RP8产品原型设计快速上手指南》一1.7 大纲面板
查看>>
《机器学习与R语言(原书第2版)》一第3章 懒惰学习——使用近邻分类
查看>>
《Python游戏编程快速上手》——2.4 本章小结
查看>>
《配置管理最佳实践》——2.13 结论
查看>>
《Python金融大数据分析》一导读
查看>>
数据挖掘与数据化运营实战. 3.3 运营群体的活跃度定义
查看>>
Storm-源码分析- hook (backtype.storm.hooks)
查看>>
BTrace使用简介
查看>>
ROS机器人程序设计(原书第2版)2.4.3 创建ROS功能包和综合功能包
查看>>
Akka笔记之消息传递
查看>>
《企业大数据系统构建实战:技术、架构、实施与应用》一1.3 本章小结
查看>>
为什么不能用memcached存储Session?
查看>>