Effective C++学习第十天

条款36:绝不重新定义继承而来的non-virtual函数

          non-virtual函数执行的是静态绑定,在编译器就已经决定,因此对象对用的函数只和指针的类型有关,而与指针所指的对象无关;记住non-virtual函数的性质:不变性凌驾于特异性;

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

         静态类型是指在程序中声明时使用的类型,动态类型是指目前所指对象的类型,动态类型变现为一个对象将会有什么样的行为;

      non-virtual和参数缺省值执行的是静态绑定,virtual执行的是动态绑定,代码分析:

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 *pr=new rectangle;

        pr->draw( );//执行的代码为rectangle::draw(shape::red):

                          //相当于shape执行缺省,rectangle执行virtual函数,一人一半,神奇的操作;

C++这样设计的原因:运行期效率,如果缺省值是动态绑定,编译器就必须用某种方法在运行期为virtual函数决定适当的参数缺省值,这比目前实现的在编译期决定的机制更慢更加复杂;

条款38:通过复合塑模出has-a或者根据某物实现出

          复合是类型之间的一种关系,当某种类型的对象内含它种类型的对象,就是这种关系;复合有两种意义,复合意味着has-a(有一个)或is-implemented-in-terms-of(根据某物实现出);

         如何区分is-a(是一种)和is-implemented-in-terms-of(根据某物实现出)这两种关系,可以通过public继承中D继承B,D对象也是B对象,反之B对象不是D对象来判断;

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

          private继承意味着implemented-in-terms-of(复合),它只有实现部分被继承,接口部分省略;private继承纯粹是一种实现技术,它在软件设计层面上没有意义,其意义只及于软件实现层面;代码分析:

      class person {...};

      class student:private person{ . . .};

      void eat(const person&p);

      person p;    student s;      eat(p);

      eat(s);//编译不通过

原因:1)private继承中编译器不会自动将一个derived class对象转换为一个base class对象;2)private继承而来的所有成员在derived  class中都会变成private属性,纵使它们在base class中原本是public或者protected;   

       尽可能的多用复合,必要的时候才使用private继承(protected成员和virtual函数牵涉进来的时候,或者继承一个empty class时候可以采用private继承)

       需求:定义一个类B(继承一个类B_B),使得这个类的派生D不能调用B_B的成员函数;

设计1:private继承

class B_B{                                           class D:private B_B{

public:                                                 private: 

       explicit B_B(int tickfrency);                              virtual void ontick( ) const;

       virtual void ontick( )const;

};                                                        };

设计2:继承+复合

class D{

private:

        class widgettimer:public B_B{

         public:   

                           virtual void ontick( )const;

                              ...

        };

    widgwttimer timer;

}

在D内声明一个嵌套式private class,后者以public继承B_B并重新定义ontick,然后放这个类型在D对象内;

选择方案2不选择方案1的原因:1)想阻止D的derived class重新定义ontick函数;2)降低D编译的依存性;

          empty class:没有non_static成员变量,没有virtual函数,没有virtual base class;empty class数据大小并不是零,C++规定凡是独立对象都必须有非零大小(这个约束不针对derived class 中的base class成分,它们是非独立的),因此一个empty class 大小为1(C++规定安插一个char类型到空对象中);

         在继承empty class中,如果选择private继承(EBO,empty base optimization,继承空类),可能造成empty base的最优化;

猜你喜欢

转载自blog.csdn.net/xx18030637774/article/details/80881744