Part6 继承与OOD Inheritance and Object-Oriented Design(二)

  • Rule37 :绝不重新定义继承而来的缺省参数值
    Never redefine a function’s inherited default parameter value.
    由于重新定义一个继承而来的Non-virtual函数永远是错误的,所以可以安全地将本条款的讨论局限于”继承一个带有缺省参数值的Virtual函数”。
#include "stdafx.h"
#include <iostream>
using namespace std;

class Shape{

public:
    enum ShapeColor{Red,Green,Blue};
    virtual void draw(ShapeColor color = Blue) const = 0;//blue = 2

};

class Rectangle : public Shape
{
public:
    virtual void draw(ShapeColor color = Green) const{
        //赋予不同的缺省参数值,这容易出现错误
        cout<<"draw color is "<<color<<endl;
    }
};

class Circle : public Shape
{
public:
    virtual void draw(ShapeColor color) const{
        cout<<"draw color is "<<color<<endl;
    }
    //以上这么写则当客户已对象调用此函数,一定要指定参数值。因为静态绑定下这个函数并不从其base继承缺省参数值。
    //若以指针或引用调用此函数,可以不指定参数值,因为动态绑定下这个函数会从其base继承缺省参数值
};


int _tmain(int argc, _TCHAR* argv[])
{

    Rectangle rec;
    rec.draw(); // Green
    Shape &ss = rec;
    ss.draw();//传递的是基类的blue,所以这种情况下,就会让调用产生误解
    Circle cir;
    cir.draw(Shape::Blue);这种方式必须为其提供参数值
    Shape& s = cir;
    s.draw();//这种动态绑定,默认参数可以传递给继承类进行调用。 显示的值为Blue 2

    getchar();
    return 0;
}

究其原因是当考虑带有缺省参数值的Virtual函数时,Virtual函数时动态绑定,而缺省参数值却是静态绑定。就是说可能会在“调用一个定义于Derived class内的Virtual函数”的同时,却使用base class为它所指定的缺省参数值。就像上面所示的例子。
以上事实在将引用换成指针的情况下,仍然存在。重点在于draw是个virtual函数,而它有个缺省参数值在derived class中被重新定义。
为什么C++坚持这种方式来运行呢?答案在于运行期效率。如果缺省参数值是动态绑定,编译器就必须有某种办法在运行期为Virtual函数决定适当的参数缺省值,这比目前实行的“在编译期决定”的机制更慢而且更复杂。为了执行速度和编译器实现上的简易,C++做了这样的取舍。

解决方案:
当你想令Virtual函数表现出你所想要的行为遭到问题时,聪明的做法是考虑替代设计。替代设计之一是NVI(non-virtual interface)手法:令base class内的一个public non-virtual 函数调用private Virtual函数,后者可被Derived classes重新定义。这里可以让non-virtual函数指定缺省参数,而private Virtual函数负责真正的工作。
Part6 继承与OOD Inheritance and Object-Oriented Design(二)_第1张图片

class Shape{

public:
    enum ShapeColor{Red,Green,Blue};
    void draw(ShapeColor color = Red) const
    {
        doDraw(color);
    }
private:
    virtual void doDraw(ShapeColor color) const = 0;
};

class Rectangle : public Shape
{
private:
    virtual void doDraw(ShapeColor color) const
    {
        cout<<"this is the "<<color<<endl;
    }

};


int _tmain(int argc, _TCHAR* argv[])
{


    ////问题所在地
    //Rectangle rec;
    ////rec.draw();
    //Shape &ss = rec;
    //ss.draw();

    //Circle cir;
    ////cir.draw(Shape::Blue);
    //Shape& s = cir;
    //s.draw();


    //使用NVI(non-virtual interface)方法解决
    Rectangle rec;
    rec.draw(Shape::Blue);
    Shape &ss = rec;
    s.draw(); //现在这两种调用一致了

    getchar();
    return 0;
}

你可能感兴趣的:(Part6 继承与OOD Inheritance and Object-Oriented Design(二))