条款37:绝不重新定义继承而来的缺省参数

在继承中,分为两类函数:virtual和non-virtual。而重新定义一个非虚函数是不好的(条款36),那么以下的讨论就是如何定义继承而来的虚函数。

强调:虚函数是动态绑定的,而缺省参数值是静态绑定的。

 1 #include <iostream>
 2
 3 class Shape
 4 {
 5 public:
 6     enum ShapeColor{ Red, Green, Blue };
 7     virtual void draw(ShapeColor color = Red) const = 0;
 8 };
 9
10 class Rectangle : public Shape
11 {
12 public:
13     virtual void draw(ShapeColor color = Green) const;  // 混淆设计:重新定义了继承而来的缺省参数值
14 };
15 void Rectangle::draw(ShapeColor color) const
16 {
17     std::cout << color << std::endl;
18 }
19
20 class Circle : public Shape
21 {
22 public:
23     virtual void draw(ShapeColor color) const;  //
24 };
25 void Circle::draw(ShapeColor color) const
26 {
27     std::cout << color << std::endl;
28 }
29
30 int main()
31 {
32     Shape* ps;                             // 静态类型为Shape*
33     Shape* pr = new Rectangle;         // 静态类型为Shape*
34     Shape* pc = new Circle;              // 静态类型为Shape*
35
36     pr->draw();                            // 相当于调用了Rectangle::draw(Shape::Red)
37     pr->draw(Rectangle::Green);            // 调用Rectangle::draw(Rectangle::Green)
38     pc->draw(Circle::Blue);                // 调用Circle::draw(Circle::Blue)
39
40     return 0;
41 }
42         

说明:

关于类型:ps、pr、pc不论其指向什么,静态类型都为Shape*。所谓动态类型,就是当前所指对象的类型,如,pr的动态类型是Rectangle*,pc的动态类型是Circle*,ps未指向任何对象,因此没有动态类型。

关于重定义缺省值:如上例中的pr->draw(),我们的本意可能是调用Rectangle::draw(Rectangle::Green),可实际上调用的是Rectangle::draw(Shape::Red),结果就是:调用的是派生类的函数,而使用的却是基类的默认参数,真是不伦不类。导致这种结果的原因就是:缺省参数值是静态绑定的,其总是根据pr的静态类型去寻找默认参数值,我们必须避免这种糟糕的设计。

时间: 2024-08-27 13:23:16

条款37:绝不重新定义继承而来的缺省参数的相关文章

Effective C++ Item 37 绝不重新定义继承而来的缺省参数值

本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 经验:绝对不要重新而来的缺省参数值,因为缺省参数值都是静态绑定,而 virtual 函数 -- 你唯一应该覆写的东西 -- 却是动态绑定 示例: class Shape{ public: enum ShapeColor {Red, Green, Blue}; virtual void draw(ShapeColor color = Red) const = 0; }; class Rect

C++ 静态绑定与动态绑定------绝不重新定义继承而来的缺省参数

在了解静态绑定和动态绑定之前,先了解什么是对象的静态类型,什么是对象的动态类型. 对象的静态类型:对象在声明时采用的类型.是在编译器决定的. 对象的动态类型:目前所指对象的类型.是在运行期决定的. 动态类型可以更改,而静态类型不可更改.看一个示例 class Base { public: void setData(int i=10) { cout <<" virtual int Base::setData()"<<endl; } virtual int getD

Effective C++:条款37:绝不重新定义继承而来的缺省参数值

由于重新定义继承而来的non-virtual函数是不正确的(见上一个条款),所以这个条款就将问题局限于:绝不重新定义继承一个带有缺省参数值的virtual函数. (一) virtual函数是动态绑定的,而缺省参数却是静态绑定. 对象的所谓静态类型,是它在程序中被声明时所采用的类型. 你可能会在"调用一个定义于derived class 内的virtual函数"的同时,却使用了base class为它所指定的缺省参数值. (二) 为什么继承而来的virtual函数的缺省参数值不能被重新定

Item 37:绝不重新定义继承而来的缺省参数值

Item 37:绝不重新定义继承而来的缺省参数值 Item 37:Never redefine a function's inherited default parameter value 本条款的讨论局限于:继承一个带有缺省参数值的virtual函数. 本条款成立的理由是:virtual函数是动态绑定(dynamically bound),而缺省参数却是静态绑定(statically bound). 静态绑定又名前期绑定,early binding:动态绑定又名后期绑定,late bindin

c++ 切勿重新定义继承来的带缺省参数的函数

切勿重新定义继承来的带缺省参数的函数.我们知道,继承来的函数是virtual 的,至于原因在上一节中已经说明了,即“切勿重新定义父类non-virtual函数”.所以确切的描述应该是“切勿重新定义继承来的带缺省参数的virtual函数”.因为缺省参数是静态绑定,而virtual是动态绑定. typedef enum _ColorEnum{ eRed = 1, eYellow, eBlack }ColorEnum; class BaseOption { public: BaseOption(voi

effective C++中条款37:绝不重新定义继承而来的缺省参数值

virtual 函数会动态绑定,而virtual函数的缺省参数值是静态绑定的.用一个base类型的指针p去指向一个derived类对象,通过p调用虚函数时,会动态绑定到实际所指对象中的函数:用一个derived类型的指针p2指向一个derived对象,由p2调用函数时,直接就是调用的derived中的函数,其参数值也是derived类中函数对应的参数值. #include <iostream> using namespace std; class A { public: enum Color

绝不重新定义继承而来的缺省参数值

考虑如下的代码: 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

[条款36]绝不重新定义继承而来的non-virtual函数

看下面的两个类的声明代码: class B { public: void mf(); //something to do }; class D : public B { public: void mf(); }; 如果有下面的调用: D x; //第一种调用 B *pB = &x; pB->mf();//调用B::mf //第二种调用 D *pD = &x; pD->mf();//调用D::mf 这两种调用的行为是不一样的,虽然从表面上看,两者都是通过对象x调用成员函数mf,凭

Effective C++ 条款36 绝不重新定义继承而来的non-virtual函数

1. public继承意味着is-a关系,即派生类是基类的一种,任何基类可以进行的操作派生类也应该可以进行,如果派生类对于某个函数的实现与基类不同,那么就应当这个函数设为virtual,如果基类中的某个函数是non-virtual的,那么也应该意味着派生类应该继承这个函数的实现,而不应该重定义它. 2. 由于non-virtual函数采用静态绑定,如果对其进行重定义,那么经由指向派生类对象的基类指针调用的non-virtual函数将会是基类版本,这与期望不同,因此要override就设为virt