EffectiveC++学习笔记-条款36|37

来源:互联网 发布:甲骨文 ibm做啥软件 编辑:程序博客网 时间:2024/05/29 12:57

条款36 决不重新定义继承而来的non-virtual函数
条款37 决不重新定义继承而来的缺省参数值

决不重新定义继承而来的non-virtual函数

正常情况下non-virtual的函数就应该是被设计的目的之一就是为了不能让子类重写。
看个简单例子:

class Base{public:    oid print()    {        cout << "Base:Print" << endl;    }};class Derived : public Base{public:    void print()    {        cout << "Derived:Print" << endl;    }};int main(){    Base* pb = new Base;    Base *pd = new Derived;    pb->print();    pd->print();    while (1) {}    return 0;}//打印结果Base:PrintBase:Print

这应该不是我们想要的结果,如果是non-virtual一定不要重写,需要重写的不要设计成non-virtual。

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

这个情况出现的次数可能不多,但是有一些需要关注的地方,例如:

//基类class Shape{public:    enum ColorType { Red, Blue, Green};    virtual void drawColor(ColorType type = Red) const = 0;};class Rect : public Shape{public:    virtual void drawColor(ColorType type = Green) const    {        cout << "drawColor:" << type << endl;    }};class Circle : public Shape{public:    virtual void drawColor(ColorType type = Blue) const    {        cout << "drawColor:" << type << endl;    }};int main(){    Shape* rect = new Rect();    Shape* circle = new Circle();    rect->drawColor();    circle->drawColor();}//打印结果  两个子类的打印结果都是 0  也就是ReddrawColor:0drawColor:0

回顾一下虚函数的知识,如果父类中存在有虚函数,那么编译器便会为之生成虚表与虚指针,在程序运行时,根据虚指针的指向,来决定调用哪个虚函数,这称之与动态绑定,与之相对的是静态绑定,静态绑定在编译期就决定了。

实现动态绑定的代价是比较大的,所以编译器在函数参数这部分,并没有采用动态绑定的方式,也就是说,默认的形参是静态绑定的,它是编译期就决定下来了。

rect的静态类型是Shape*,动态类型才是Rect*,类似地,circle的静态类型是Shape*,动态类型是Circle*。这里没有带参数,所以使用的是默认的形参,即为静态的Shape::drawColor()里面的缺省值RED,所以两个问题所在处的输出值都是0(也就是red)。

正因为编译器并没有对形参采用动态绑定,所以如果对继承而来的虚函数使用不同的缺省值,将会给读者带来极大的困惑,试想一下下面两行代码:

Shape *rect = new Rect(); // 默认值是REDRect *rect_temp = new Rect(); // 默认值是GREEN

解决办法

有问题就会有解决方法:
我们可以使用non-virtual调用virtual函数。

//基类class Shape{public:    enum ColorType { Red, Blue, Green };    void draw(ColorType type = Red) const //子类不必实现该函数    {        drawColor(type);    }private:    //真正处理工作的地方    virtual void drawColor(ColorType type) const = 0;};class Rect : public Shape{public:private:    virtual void drawColor(ColorType type) const    {        cout << "drawColor:" << type << endl;    }};class Circle : public Shape{public:private:    virtual void drawColor(ColorType type) const    {        cout << "drawColor:" << type << endl;    }};int main(){    Shape* rect = new Rect();    Shape* circle = new Circle();    rect->draw();    circle->draw();    Rect* rect_temp = new Rect();    rect_temp->draw();}

这样继承得到的子类的默认参数都是Red。

原创粉丝点击