标签:c++ effective c++ 语法优化
(六).继承与面向对象设计
____________________________________________________________________________________________________________________________________
条款35:考虑virtual函数以外的其他选择
#1.virual函数的四个替代方案://考虑以下代码: class GameCharacter{ public: int healthValue() const //derived classes不重新定义它 { //见36条款 ... //做一些事前工作,详下 int retVal = doHealthValue(); //做真正的工作 ... //做一些事后工作 } ... private: virtual int doHealthValue() const //derived classes可重新定义它 { ... } }; //我们称healthValue函数为virutal函数doHealthValue的外覆器, //它提供了完整实现,而virtual函数则提供了具体实现, //通过NVI手法,我们可以更专注于事件如何被具体完成
//考虑以下代码: class GameCharacter; //前置声明(forward declaration) //以下函数是计算健康指数的缺省算法 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; }; //同一人物类型之不同实体可以有不同的健康计算函数,例如: class EvilBadGuy:public GameCharacter{ public: explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc) : GameCharacter(hcf) {...} ... }; int loseHealthQuickly(const GameCharacter&); //健康函数计算函数1 int loseHealthSlowly(const GameCharacter&); //健康函数计算函数2 EvilBadGuy ebg1(loseHealthQuickly); //相同类型的人物搭配 EvilBadGuy ebg2(loseHealthSlowly); //不同的健康计算方式 //defualtHealthCalc并未访问EvilBadGuy的non-public成分, //若要访问non-public成分,需使其成为friends,因此可能 //降低class的封装性。 //运用函数指针替换virtual函数,其优点(像是"每个对象 //可各自拥有自己的健康计算函数”和“可在运行期改变计算 //函数”)是否足以弥补缺点(例如可能降低GameCharacter //的封装性),是你必须根据设计情况而抉择的。
//考虑以下代码: class GameCharacter; int defaultHealthCalc(const GameCharacter&); class GameCharacter{ public: //HealthCalcFunc可以是任何 “可调用物” (callable entity), //可被调用并接受任何兼容于 GameCharacter 之物,返回任何 //兼容于 int 的东西。详下。 typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc; explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc) : healthFunc(hcf) {} int healthValue() const {return healthFunc(*this);} ... private: HealthCalcFunc healthFunc; }; //如今的tr1::function相当于一个指向函数的泛化指针, //它在“指定健康计算函数”这件事上具有更惊人的弹性: short calcHealth(const GameCharacter&); //健康计算函数 //注意其返回类型为non-int struct healthCalculator{ //为计算健康而设计的函数对象 int operator()(const GameCharacter&) const {...} }; class GameLevel{ public: float health(const GameCharacter&)const; //成员函数,用以计算健康; ... //注意其non-int 返回类型 }; class EvilBadGuy:public GameCharacter{ //同前 ... }; class EyeCandyCharacter:public GameCharacter{ //另一个人物类型; ... //假设其构造函数与 }; //EvilBadGuy相同 EvilBadGuy ebg1(calcHealth); //人物1,使用某个 //函数计算健康函数 EveCandyCharacter ecc1(HealthCalculator()); //人物2,使用某个 //函数对象计算健康函数 GameLevel currentLevel; ... EvilBadGuy ebg2( //函数3,使用某个 std::tr1::bind(&GameLevel::health, //成员函数计算健康函数 currentLevel, _1,) //详见以下 ); //使用tr1::function的好处是允许使用任何可调用物, //只要其调用形式兼容于签名式
//考虑以下代码: class GameCharacter; class HealthCalcFunc{ public: ... virtual int calc(const GameCharacter& gc) const { ... } ... }; HealthCalcFunc defaultHealthCalc; class GameCharacter{ public: explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc) : pHealthCalc(phcf) {} int healthValue() const { return pHealthCalc->calc(*this); } ... private: HealthCalcFunc* pHealthCalc; }; //这个解法的吸引力在于,它提供“将一个既有的健康算法纳入 //使用”的可能性---只要为HealthCalcFunc 继承体系添加一个 //derived class 即可。____________________________________________________________________________________________________________________________________
class B{ public: void mf(); ... }; class D:public B { public: void mf(); ... }; D x; B* pB = &x; D* pD = &x; pB->mf(); //调用B::mf() pD->mf(); //调用D::mf() //对于调用同一个对象x,却出现了不同行为, //这不是我们所希望的,与其如此重新定义, //还不如让其成为virtual函数理由(2).继承下来的函数分为virtual和non-virtual, virtual意味着
//一个用以描述几何形状的class class Shape{ public: enum ShapeColor { Red, Green, Blue }; //所有形状都必须提供一个函数,用来描绘自己 virtual void draw(ShapeColor color = Red) const = 0; ... }; class Rectangle:public Shape{ public: //注意,赋予不同的缺省参数值。真实糟糕! virtual void draw(ShapeColor color = Green) const; ... }; class Circle:public Shape{ public: virtual void draw(ShapeColor color) const //请注意,以上这么写则当客户以对象调用此函数,一定要指定参数值。 //因为静态绑定下这个函数并不从其base 继承缺省参数值。 //但若以指针(或reference) 调用此函数,可以不指定其参数值, //因为动态绑定下这个函数会从其base继承缺省参数值 ... }; //现考虑以下指针: Shape* ps; //静态类型为Shape* Shape* pc = new Circle; //静态类型为Shape* Shape* pr = new Rectangle; //静态类型为Shape* pc->draw(Shape::Red); //调用Circle::draw(Shape::Red) pr->draw(Shape::Red); //调用Rectangle::draw(Shape::Red) //此代码的virtual函数是动态绑定,而缺省参数值却是静态绑定 //这造成了一种奇怪的调用方式,不能统一调用,而编译器之所以 //不为缺省参数值动态绑定的原因是运行期效率。 //那么我们是否可以为derived指定同样的缺省值呢?,就像这样: class Rectangle:public Shape{ public: virtual void draw(ShapeColor color = Red) const; ... }; //答案是否,理由很简单,这造成了我们的代码重复, //而且带有相依性,要是哪天修改了缺省值就要动辄牵动全身了。 //一种更好的做法是让non-virtual指定缺省值来代替工作: class Shape{ public: enum draw(ShapeColor color = Red) const //如今它是一个non-virtual { doDraw(color); //调用一个virtual } ... private: virtual void doDraw(ShapeColor color)const = 0; //真正的工作在此处完成 }; class Rectangle:public Shape{ public: ... private: virtual void doDraw(ShapeColor color)const; //无须指定缺省值 ... }; //由于non-virtual函数绝不被derived class覆写,这个设计很清楚地使得 //draw 函数的color 缺省参数值总是为 true.____________________________________________________________________________________________________________________________________
//例如我们要使用Timer中的功能,我们可以implemented-in-terms-of class widget:private Timer{ private: //private权限:避免客户调用 virtual void onTick() const; //重新定义我们所需的onTick函数功能 ... };
class Widget{ private: class WidgetTimer:public Timer{ public: virtual void onTick() const; ... }; WidgetTimer timer; ... }; //这种设计的好处是: //(1).它可以拥有自己的derived class. //(2).将编译依存性降至最低(分离,相依于声明式)
class Empty{}; class HoldsAnInt:private Empty{ private: int x; } //几乎可以确定,sizeof(HoldsAnInt) = sizeof(int)
class IPerson{ //该class指出需实现接口 public: virtual ~IPerson(); virtual std::string name() const = 0; virtual std::string birthDate() const = 0; virtual std::string birthDate() const = 0; }; class DatebaseID{...}; //稍后被使用,细节不重要。 class PersonInfo{ //这个class有若干有用函数 public: //可用以实现IPerson接口。 explicit PersonInfo(DatabaseID pid); virtual ~PersonInfo((); virtual const char* theName() const; virtual const char* theBirthDate() const; virtual const char* valueDelimOpen() const; virtual const char* valuedelimClose() const; ... }; class CPerson:public IPerson, private PersonInfo{ //注意,多重继承 public: explicit CPerson(DatabaseID pid):PersonInfo(pid){} virtual std::string name() const //实现必要的IPerson函数 {return PersonInfo::theName();} virtual std::string birthDate() const //实现必要的IPerson函数 {return PersonInfo::theBirthDate();} private: const char* valueDelimOpen() const {return "";} //重新定义继承而来的 const char* valueDelimClose() const {return "";}//virtual ”界限函数“ };
____________________________________________________________________________________________________________________________________
标签:c++ effective c++ 语法优化
原文地址:http://blog.csdn.net/beyond_ray/article/details/43792291