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

细读《Effective C++》之九

2013年10月17日 ⁄ 综合 ⁄ 共 2487字 ⁄ 字号 评论关闭
文章目录

Chapter 6. Inheritance and Object-Oriented Design

 

条款36:Never redefine an inherited non-virtual function

class B {
public
:
  
void
 mf();
  ...
};

class D: public B {
public
:
  
void
 mf();
 ... 
 };

D x;                              // x is an object of type D
*pB = &x;                       // get pointer to x
pB->mf();                         // calls B::mf
*pD = &x;                       // get pointer to x
pD->mf();                         // calls D::mf

non-virtual functions是statically bound,此处mf的调用取决于其声明类型而非所指对象;virtual functions是dynamically bound,如果mf是virtual function,其调用将取决于其所指对象,即D。

这儿,出于以下两点原因,Never redefine an inherited non-virtual function:

1) public inheritance应保证is-a关系。

2) non-virtual function的不变性(invariant)应凌驾于特异性(specialization)。

Things to Remember

1) Never redefine an inherited non-virtual function.

条款37:Never redefine a function's inherited default parameter value

redefine a function,那么这个function一定是virtual function了,virtual functions are dynamically bound, but default parameter values are statically bound。

// a class for geometric shapes
class Shape {
public
:
  
enum
 ShapeColor { Red, Green, Blue };
  
// all shapes must offer a function to draw themselves

  virtual void draw(ShapeColor color = Red) const = 0;
  ...
};

class Rectangle: public Shape {
public
:
  
// notice the different default parameter value — bad!

  virtual void draw(ShapeColor color = Green) const;
  ...
};

Shape *ps = new Rectangle;       // static type = Shape*, dynamic type = Rectangle*
ps->draw(Shape::Red);            // calls Rectangle::draw(Shape::Red)
ps->draw();                      // calls Rectangle::draw(Shape::Red)!

由于ps的dynamic type是Rectangle,所以解析为Rectangle::draw(),由于ps的static type是Shape,所以解析为Rectangle::draw(Shape::Red)。

因此,应将带default parameter value的函数声明为non-virtual,其实现用一个private virtual function完成:

class Shape {
public
:
  
enum
 ShapeColor { Red, Green, Blue };
  
void draw(ShapeColor color = Red) const           // now non-virtual

  {
    doDraw(color);                                  
// calls a virtual

  }
  ...

private:
  
virtual void doDraw(ShapeColor color) const = 0;  // the actual work is

};                                                  // done in this func

class Rectangle: public Shape {
public
:
  ...

private:
  
virtual void doDraw(ShapeColor color) const;       // note lack of a

  ...                                                // default param val.
};

Things to Remember

Never redefine an inherited default parameter value, because default parameter values are statically bound, while virtual functions — the only functions you should be overriding — are dynamically bound. 

Item 36 - 37
 

抱歉!评论已关闭.