effective C++条款三十五解读

来源:互联网 发布:西北师范大学知行诱骗 编辑:程序博客网 时间:2024/06/07 15:45

考虑virtual函数以外的其他选择

我们一个游戏软件的血量计算方法为例来讲解这个主题,我们在游戏中有不同的游戏人物,不同游戏人物的血量计算方式不同,这驱使我们写出这样的面向对象代码。

class GameCharacter{public:     virtual int healthValue() const =0;//我们可以为纯虚函数实现一份默认定义,派生类是否选用是他们的权利。}
这里我们的实现是public的virtual形式。

这么一个简单的实现可以延伸出很多不同但既有优点又有缺点的做法:

1.借助non-virtual Interface(NVI)手法实现Template Method(一种设计模式)。其实就是在虚函数外面包裹了一层调用。

2.借助(函数指针以及函数对象)实现的strategy模式。

3.古典的strategy设计模式。

借助NVI的手法;

class GameCharacter{public:int healthValue() const{//1.做一些事前工作int retVal=doHealthValue();//2.做一些事后工作。return retValue。}private:virtual int doHealthValue() const;}
这种方法我们通过public的非虚函数调用其私有的虚函数来实现,允许在多态调用前,进行一些设置工作,有一些特化的功能交给派生来处理。这种方法就是模板方法。这种方法其实没有摆脱虚函数,只是加了一层封装而已。

我们再来看借助函数指针以及函数对象来实现的strategy模式:

用代码来进行讲解

class  GameCharacter;int defaultHealthCalc(const GameCharacter&);class GameCharacter{public:typedef int(*healthCalcFunc)(const GameCharacter);GameCharacter(HealthCalcFunc hcf=defaultHealthCalc):healthFunc(hcf){}private:healthCalcFunc  healthFunc; };
这种方式的好处的有两个:

1.同一个人物类型之不同实体可以有不同的健康计算函数。

2.同一个实体的健康计算函数也可以在运行期改变。通过设置健康计算函数。

但是随之而来也产生了一些问题,比如首先这个外部提供的函数可能无法访问私有变量,如果通过一些函数访问私有变量,就降低了类的封装性。

利用函数对象实现的strategy方式就提供了更佳的弹性:可以用所用的可调用对象对其复制,可进行一些转换。

class GameCharacter;int defalueHealthFunc(const GameCharacter&);class GameCharacter{pubclic:typedef function<int(const GameCharacter&)> healthCalcFunc;explicit GameCharacter(HealthCalcFunc hcf=defaultHealthCalc):healthFunc(hcf){}int healthValue() const{return healthFunc(*this);}private:HealthCalcFunc healthFunc;};

利用以上函数我们可以完成许多函数指针没有办法完成的事情:

short calcHealth(const GameCharacter&);//注意这个函数的返回类型是short,可以转换成int型。struct HealthCalculator{int operator()(const GameCharacter&) const;}struct GameLevel{public:float health(const GameCharacter&) const;//注意返回类型是float }GameCharacter gc1(calcHealth);GameCharacter gc2(HealthCalculator());GameLeve gl;GameCharacter gc3(bind(&GameLevel::health,gl,-1));