Effective C++读书笔记11(37~40)

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

本条款成立的理由非常明确:virutal函数系动态绑定,而缺省参数值却是静态绑定。

对象的静态类型,就是他在程序被声明时所采用的类型。考虑以下的class继承体系:

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

class Recgangle: public Shape{
public:
	virutal void draw(ShapeColor color = Green) const;
	//...
};
class Circle: public Shape{
public:
	virutal void draw(ShapeColor color) const;
        //请注意:以上这么写则当客户以对象调用此函数,一定要指定参数值。
        //因为静态绑定下这个函数并不从其base继承缺省参数值。
        //但若以指针或者引用调用此函数,可以不指定参数值,因为动态绑定下这个函数会从其base继承缺省参数值。
 };

现在考虑以下指针:

Shape* ps;                                  //静态类型为Shape*

Shape* pc = new Circle;          //静态类型为Shape*

Shape* pr = new Rectangle;  //静态类型为Shape*

ps, pc,pr都被声明为pointer-to-shape类型,所以它们都为静态类型。不论他们真正指向什么,他们的静态类型都是shape*。

对象的所谓动态类型则是指目前所值对象的类型,pc的动态类型是Circle*, pr的动态类型是Rectangle*。ps没有动态类型,因为它尚未指向任何对象。动态类型可以在执行过程中改变:

ps = pc;       //ps的动态类型如今是Circle*

ps = pr;       //ps的动态类型如今是Recrangle*

virtual函数系动态绑定而来,意思是调用一个virutal函数时,究竟调用哪一份函数实现,取决于发出调用的那个对象的动态类型:

pc->draw(Shape::Red);     //调用Circle::draw

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


当时考虑带有缺省参数值的virtual函数时:virtual函数是动态绑定,而缺省参数却是静态绑定,即可能会在调用一个定义于derived类内的virtual函数时,却使用base类为它指定的缺省参数值:

pr->draw();         //调用Rectangle::draw(Shape::Red)!!   pr的动态类型的默认参数是Green,但是这里却使用的是静态绑定的基类的默认参数Red。


为什么C++坚持以这种方式运作呢?答案在于运行期效率。如果缺省参数是动态绑定,编译器就必须有某种办法在运行期为virtual函数决定适当的参数缺省值。这比目前实行的在编译期决定的机制更慢而且更复杂。为了程序的执行速度和编译器实现上的简易度,C++做了这样的取舍。

如果让基类的默认参数和derived类的默认参数相同就可以了,但是很明显,这会带来代码上的重复,而且会带来相依性,如果一个改变,其他的都要改变。所以这里可以考虑替代设计,见条款35中诸多virtual函数的替代设计。

请记住:

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


条款38:通过复合塑模出has-a或者"根据某物实现出"(没怎么看懂)

条款39:明智而审慎的使用private继承

条款40:明智而审慎的使用多重继承




你可能感兴趣的:(C++,c,读书,Class,编译器)