现在的位置: 首页 > 综合 > 正文

《Effective C++》读书笔记之item35:考虑virtual函数以外的其他选择

2013年08月18日 ⁄ 综合 ⁄ 共 2472字 ⁄ 字号 评论关闭

1.虚函数的替代方案有:

  • (1)使用non-virtual interface(NVI)方法,它是Template Method设计模式的一种特殊形式。使客户通过仅有的非虚函数间接调用私有的虚函数,该公有的非虚函数称为私有虚函数的“外覆器”(wrapper)。公有的非虚函数可以在调用虚函数前后做一些其他工作(如互斥器的锁定与解锁,验证约束条件等)。
  • (2)将虚函数替换为“函数指针成员变量”,它是Strategy设计模式的一种分解表现形式。
  • (3)以tr1::function成员变量替换虚函数,从而允许使用任何可调用物搭配一个兼容于需求的签名式(这句话表达太晦涩了,很难理解,例子见下)。它也是Strategy设计模式的某种形式。
  • (4)将继承体系内的虚函数替换为另一个继承体系内的虚函数,这是Strategy设计模式的传统实现手法。

2.考虑案例:游戏中的人物伤害值计算问题。

(1)一般来讲可以使用虚函数的方法:

class GameCharacter{
	public:
		virtual int healthValue() const;	//返回人物的体力值,派生类可以做出修改
		...
};

(2)使用NVI方法,在基类中使用一个公有的普通函数调用私有的虚函数。

class GameCharacter{
	public:
		int healthValue() const {		//派生类不能重新定义它
			...			//做一些事前工作
			int retVal = doHealthValue();		//调用私有函数进行计算
			...			//做一些事后工作
			return retVal;
		}
	...
	private:
		virtual int doHealthValue() const{		//派生类可以重新定义
			...			//提供缺省算法
		}
}; 

(3)使用函数指针。

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;
};

这种方法能够:

  • 〈1〉通过定义不同的体力值计算方法,同种类型的人物通过调用不同的函数可以实现不同的计算方法。
  • 〈2〉人物的体力计算方法可以在运行期间变更(相当于为GameCharacter的私有变量重新赋值)。

这种方法(包括以后的两种方法)可能会使用类外的函数,从而降低封装性。

(4)使用tr1::function完成Strategy模式。

class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);
class GameCharacter{
	public:
		//HealthCalcFunc可以是任何“可调用物”,可被调用并接受任何兼容于GameCharacter之物,返回任何兼容于int的东西,详下:
		typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;
		//这种定义表示HealthCalcFunc作为一种类型,接受GameCharacter类型的引用,并返回整数值,其中支持隐式类型转换
		explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf)
		{}
		int healthValue() const{
			return healthFunc(*this);
		}
		...
	private:
		HealthCalcFunc healthFunc;
};

在使用这个方法时P175介绍了三种调用方式,即使用三种方式初始化GameCharacter的派生类:一个具体的函数,一个函数对象,以及一个像std::tr1::bind(&GameLevel::health, currentLevel, _1)这样用一个对象的成员函数。

EvilBadGuy ebg1(calcHealth);		//使用某个函数
EyeCandyCharacter ecc1(HeathCalculator());		//使用某个函数对象(包含一个函数的结构体)
GameLevel currentLevel;
EvilBadGuy ebg2(std::tr1::bind(&GameLevel::health, currentLevel, _1));

(5)使用典型的Strategy。类图如下:

在GameCharacter类中的具体定义为:

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

3.Strategy模式:在《设计模式》中,定义为:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。Strategy模式使算法可独立于使用它的客户而变化。 

Strategy模式以下面几条原则为基础:

  • 1)  对象都具有职责;
  • 2)  这些职责不同的具体实现是通过多态的使用完成的;
  • 3)  概念上相同的算法具有多个不同的实现,需要进行管理。

注:摘自http://blog.csdn.net/wcyoot/article/details/7522152

抱歉!评论已关闭.