细读《Effective C++》之九
2007-05-29 14:14
387 查看
http://blog.csdn.net/yulefox/archive/2007/05/15/1609670.aspx
Item 36 - 37
Chapter 6. Inheritance and Object-Oriented Design
class B {
public:
void mf();
...
};
class D: public B {
public:
void mf();
...
};
D x; // x is an object of type D
B *pB = &x; // get pointer to x
pB->mf(); // calls B::mf
D *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.
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
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
B *pB = &x; // get pointer to x
pB->mf(); // calls B::mf
D *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.
相关文章推荐
- 细读《Effective C++》之一
- 细读《Effective C++》之五
- 细读《Effective C++》之八
- 细读《Effective C++》之四
- 细读《Effective C++》之十三
- 细读《Effective C++》之九
- 细读《Effective C++》之二
- 细读《Effective C++》之九
- 细读《Effective C++》之五
- 细读《Effective C++》之二
- 细读《Effective C++》之十
- 细读《Effective C++》之三
- 细读《Effective C++》之十
- 细读《Effective C++》之六
- 细读《Effective C++》之十四
- 细读《Effective C++》之三
- 细读《Effective C++》之六
- 细读《Effective C++》之七
- 细读《Effective C++》之四
- 细读《Effective C++》之十一