Edmund's zone

导航

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

考虑如下的代码:

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;    //不须指定参数值
    ...
};

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

posted on 2015-04-24 15:17  Edmund Li  阅读(278)  评论(0编辑  收藏  举报