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

考虑下面这段程序:

#include <iostream>
using namespace std;

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 {
        cout << "Rectangle::draw, color = " << color << endl;
    }
};

class Circle : public Shape {
public:
    virtual void draw(ShapeColor color) const {
        cout << "Circle::draw, color = " << color << endl;
    }
};

int main()
{
    /*
    Circle circle;
    circle.draw();      //编译出错
    */

    /*
    Shape *pc = new Circle;
    pc->draw();         //color = 0(Red)
    */

    /*
    Rectangle rtg;
    rtg.draw();         //color = 1(Green)
    */

    /*
    Shape *pr = new Rectangle;
    pr->draw();         //color = 0(Red)
    */

    return 0;
}
在分析这段程序之前,我们先明确几个概念。

静态类型:指它在程序中被声明时所采用的类型。

动态类型:指目前所指对象的类型。

例如上面的程序中,pr的动态类型是Rectangle,静态类型是Shape。

静态绑定:又名前期绑定(early binding),绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译期。

动态绑定:又名后期绑定(late binding),绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型,发生在运行期。

virtual函数是动态绑定,意思是调用一个virtual函数时,究竟调用哪一份函数的实现代码,取决于发出调用的那个动态类型。

而缺省参数值是静态绑定。

因此对于第一段代码:

Circle circle;
circle.draw();      //编译出错
当我们以对象调用此函数,必须要指定参数值,circle的静态类型是Circle,在静态绑定下,函数并不从Shape继承其缺省参数值。

对于第二段代码:

Shape *pc = new Circle;
pc->draw();         //color = 0(Red)
此时可以不用指定参数,因为pc的动态类型是Circle,静态类型是Shape,通过动态绑定,它调用的是Circle的draw函数,但是通过静态绑定它继承了Shape的缺省参数Red。

对于第三段和第四段代码的表现结果,其原因则与上面类似。

如果我们想避免上面的麻烦,我们可以使用NVI(non-virtual interface)手法去替代:令base class内的一个public non-virtual函数调用private virtual函数,后者可被derived classes重新定义。这里我们可以让non-virtual函数指定缺省参数,而private virtual函数负责真正的工作。

class Shape {
public:
    enum ShapeColor { Red, Green, Blue };
    void draw(ShapeColor color = Red) const {           //如今它是non-virtual
        doDraw(color);                                  //调用一个virtual
    }
private:
    virtual void doDraw(ShapeColor color) const = 0;    //真正的工作在此处完成
};

class Rectangle : public Shape {
public:
    
private:
    virtual void doDraw(ShapeColor color) const;        //注意,不须指定缺省参数值
};
由于non-virtual函数应该绝对不被derived classes覆写,这个设计很清楚地使得draw函数的color缺省参数值总是为Red。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值