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

考虑如下的代码:

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;
    ...
};

以上代码有个问题,如果你用下面的调用方式:

Shape *ps;
Shape *pc = new Circle;
Shape *pr = new Rectangle;

pc->draw(Shape::Red);    //Circle::draw(Shape::Red);
pr->draw(Shape::Red);    //Rectangle::draw(Shape::Red);

pr->draw();          //Rectangle::(Shape::Red)!!!!

我们会发现,pr的动态类型是Rectangle*, 所以调用的是Rectangle的virtual函数,Rectangle::draw的缺省参数应该是GREEN,但是,由于pr的静态类型是Shape*,所以此调用的缺省参数值来自Shape而不是Rectangle。C++之所以这么做,是考虑到运行时效率的问题。如果缺省参数值是动态绑定,编译器就必须在运行期为虚函数决定适当的缺省值。这比目前实行的“在编译器决定”机制更慢更复杂。

那么我们怎么做才适合呢?在派生类里面也提供缺省值吗?

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;
    ...
};

Aha,代码重复。

可以用替代设计,比如可以用基类的public 非虚函数调用private的虚函数,后者可以被派生类重新定义,而让非虚函数去做缺省参数的事情。

class Shape
{
public:
    enum ShapeColor { Red, Green, Blue };
    void draw(ShapeColor color = Red) const         //non-virtual
    {
        doDraw(color);
    }
    ...
private:
    virtual void doDraw(ShapeColor color) const = 0;//do the real work
};

class Rectangle : public Shape
{
public:
    ...
private:
    virtual void doDraw(ShapeColor color) const;    //不须指定参数值
    ...
};

绝对不要重新定义一个继承而来的缺省参数值,这些参数值都是静态的,而虚函数却是动态的。

时间: 2024-10-10 04:06:32

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

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

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

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

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

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

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

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

条款38: 决不要重新定义继承而来的缺省参数值

虚函数是动态绑定而缺省参数值是静态绑定的,当基类和派生类对同一个虚函数设置缺省参数值时,只有基类的缺省参数值起作用. 对象的静态类型是指你声明的存在于程序代码文本中的类型,对象的动态类型是由它当前所指的对象的类型决定的.即,对象的动态类型表示它将执行何种行为. 虚函数是动态绑定的,意思是说,虚函数通过哪个对象被调用,具体被调用的函数就由那个对象的动态类型决定 将虚函数和缺省参数值结合起来分析就会产生问题,因为,如上所述,虚函数是动态绑定的,但缺省参数是静态绑定的.这意味着你最终可能调用的是一个定

条款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;

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

首先,此处的函数指的是 virtual 函数,为什么不是non-virtual函数呢?是因为在public继承中,non-virtual函数表示派生类是需要继承其接口与其强制实现的.如果你的Derived已经在考虑重写non-virtual函数了,那么你是应该好好审视一下,在此处使用 public继承是否合理了. 因此,本文只讲解virtual函数的缺省参数值,例如下面的代码: 在C++代码中,函数的参数值是静态绑定的,而通过基类的指针或者引用对virtual函数调用的动态绑定的. 因此,当你的

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

(一)首先有下面的继承体系: class B { public: void mf(); ... }; class D : public B {...}; D x; 以下行为: B* pB = &x; pB->mf(); 异于以下行为: D* pD = &x; pD->mf(); 上面两种行为产生的结果不一定相同.看下面这种情况: mf是个non-virtual函数而D定义有自己的mf版本: class D : public B { public: void mf(); ...