zoukankan      html  css  js  c++  java
  • Effective C++笔记_条款35 考虑virtual 函数以外的其他选择

        因为其他的事情耽误了看书,现在将看的笔记记录下来。

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

    1. 藉由Non-Virtual Interface 手法实现 Template Method模式
    (1)non-virtual interface(NVI):
      令客户通过public non-virtual 成员函数间接调用private virtual函数
    (2) virtual 函数的外覆器(wrapper):non-virtual 函数

     1 class GameCharacter {
     2  public:
     3      int healthValue() const    // virtual 函数的外覆器(wrapper)
     4      {
     5          //...
     6          /*
     7           做些事前工作:锁定互斥器,制造运转日志记录项,验证class约束条件、验证函数先决条件等等
     8          */
     9          int retVal = doHealthValue();
    10          //...
    11          /*
    12          做些事后工作:互斥器解除锁定,验证函数的时候条件、再次验证class约束条件等等。
    13          */
    14          return retVal;
    15      }
    16  private:
    17      virtual int doHealthValue() const
    18      {
    19          //...
    20      }
    21  };

    优点:
      先比于直接调用virtual 函数,就没有任何好办法可以处理事前和时候工作。
    注意事项:
      重新定义virtual 函数,表示某些事“如何”被完成,“调用virtual 函数”则表示它“何时”被完成。

      NVI手法允许derived classs重新定义virtual函数,从而赋予他们“如何实现机能”的控制能力,但base class保留诉说“函数何时被调用”的权利。


    2.藉由Function Pointers 实现Strategy模式

     1 class GameCharacter;    // forward declaration
     2 
     3  int defaultHealthCalc(const GameCharacter& gc);    /*计算健康指数的缺省算法*/
     4  class GameCharacter {
     5  public:
     6          typedef int (*HealthCalcFunc) (const GameCharacter&);
     7          explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
     8              :healthFunc(hcf)
     9          {}
    10 
    11          int healthValue() const
    12          {
    13              return healthFunc(*this);
    14          }
    15  private:
    16      HealthCalcFunc healthFunc;
    17  };

    上述模式的解释说明:
    (1)同一任务类型的不同实体可以不同的健康计算函数。e.g:

     1 class EvilBadGuy:public GameCharacter {
     2 public:
     3     explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc)
     4         :GameCharacter(hcf)
     5     {
     6         //...
     7     }
     8 };
     9 
    10 int loseHealthQuickly(const GameCharacter&);
    11 int loseHealthSlowly(const GameCharacter&);
    12 
    13 /* 相同类型的的人物搭配不同的健康计算方式 */
    14 EvilBadGuy ebg1(loseHealthQuickly);
    15 EvilBadGuy ebg2(loseHealthSlowly);

    (2)某已知人物的健康指数计算函数可在运行期变更。

      例如GameCharacter提供一个setHealthCalculator函数,用来替换当前的健康指数计算函数。

    (3)一般而言,唯一能够解决“需要以non-member函数访问class的non-public成分”的办法是:弱化class的封装。例如,class可声明那个non-member函数为friends或为其实现的某一部分提供public访问函数。
     ----> 藉由Function Pointers 实现Strategy模式的缺点是:弱化了class的封装性。



     3.藉由tr1::function完成Strategy模式

     1 class GameCharacter;
     2  int defaultHealthCalc(const GameCharacter& gc);
     3  class GameCharacter {
     4  public:
     5          /*
     6          HealthCalcFunc 可以是任何“可调用物”(callable entity),可被调用并接受任何兼容于
     7          GameCharacter的事物(参数可被隐式转换为const GameCharacter&),
     8          返回任何兼容于int的东西(可被隐式转换为int)。
     9 
    10          类似一个指向函数的泛化指针
    11          */
    12          typedef std::tr1::function<int (const GameCharacter&)> HealthCalcFunc;
    13          explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
    14              :healthFunc(hcf)
    15          {}
    16 
    17          int healthValue() const
    18          {
    19              return healthFunc(*this);
    20          }
    21  private:
    22      HealthCalcFunc healthFunc;
    23 
    24  };
    25 
    26 /*健康计算函数,注意其返回类型为non-int*/
    27  short calcHealth(const GameCharacter&); 
    28 
    29 /*为计算健康而设计的函数对象*/
    30  struct HealthCalculator {
    31      int operator() (const GameCharacter&) const
    32      {
    33          //...
    34      }
    35  };
    36 
    37  class GameLevel {
    38  public:
    39      /*成员函数,用以计算健康;注意其non-int返回类型*/
    40      float health(const GameCharacter&) const;
    41      //...
    42  };
    43 
    44 class EvilBadGuy:public GameCharacter {
    45 public:
    46     explicit EvilBadGuy(HealthCalcFunc hcf = defaultHealthCalc)
    47         :GameCharacter(hcf)
    48     {
    49         //...
    50     }
    51 };
    52 
    53 class EyeCandyCharacter:public GameCharacter {
    54 public:
    55     explicit EyeCandyCharacter(HealthCalcFunc hcf = defaultHealthCalc)
    56         :GameCharacter(hcf)
    57     {
    58         //...
    59     }
    60 };
    61 
    62 /*使用函数计算健康指数*/
    63 EvilBadGuy ebg1(calcHealth); 
    64 /*使用某个函数对象计算健康指数*/ 
    65 EyeCandyCharacter eccl(HealthCalculator());    
    66 
    67 /*使用某个成员函数计算健康指数*/
    68 GameLevel currentLevel;
    69 EvilBadGuy ebg2(std::tr1::bind(&GameLevel::health, currentLevel, _l));

    4.古典的Strategy模式
      传统的Strategy做法会将健康计算函数做成一个分离的继承体系中的virtual成员函数

     1 class GameCharacter;
     2 class HealthCalcFunc {
     3 public:
     4     //...
     5     virtual int calc(const GameCharacter& gc) const
     6     {
     7         //...
     8     }
     9     //...
    10 };
    11 
    12 HealthCalcFunc defaultHealthCalc;
    13 class GameCharacter {
    14 public:
    15     explicit GameCharacter(HealthCalcFunc* phcf = &defaultHealthCalc)
    16         :pHealthCalc(phcf)
    17     {}
    18 
    19     int healthValue() const
    20     {
    21         return pHealthCalc->calc(*this);
    22     }
    23 
    24     //...
    25 private:
    26     HealthCalcFunc *pHealthCalc;
    27 };

    5.总结

      当你为解决问题而寻找某个设计方法时,不妨考虑virtual函数的替代方案。
      (1)使用non-vvirtual interface(NVI)手法,它以public non-virtual 成员函数包裹较低
        访问性(private或protected)的virtual函数。

      (2)将virtual函数替换为“函数指针成员变量”。

      (3)以tr1::function 成员变量替换virtual,因而允许使用任何可调用物搭配一个兼容与需求的签名式。

      (4)将继承体系内的virtual函数替换为另一个继承体系的virtual函数。


    注明:全文文字都是来源《Effective C++》 3th。这里所写都是自己的读书的时候梳理做的笔记罢了。希望对他人有用,那是我的荣幸。

  • 相关阅读:
    uva 10491 Cows and Cars
    uva 10910 Marks Distribution
    uva 11029 Leading and Trailing
    手算整数的平方根
    uva 10375 Choose and divide
    uva 10056 What is the Probability?
    uva 11027 Palindromic Permutation
    uva 10023 Square root
    Ural(Timus) 1081. Binary Lexicographic Sequence
    扩展欧几里得(求解线性方程)
  • 原文地址:https://www.cnblogs.com/cloudfeng/p/4380253.html
Copyright © 2011-2022 走看看