读书笔记六

  • 确定你的public继承塑模出is-a关系
    •   public继承和is-a的之间的等价关系很简单。例如动物和鸟,鸟一定是动物,而动物不一定是鸟。
    •   public继承意味着is-a。适用于base classes身上的每一件事情也是一定适用于派生类身上的,因为每一个派生类对象也都是一个base classes对象。


  • 避免遮掩继承而来的名称
    • int x;//global变量
      void somefunc(){
          double x;//local变量,这个变量会遮掩吊全局变量,在这个函数体内,改变的是double的x。
          cin>>x;
      }
    •   实际上类的继承中也是会发生这样的事情。派生类继承基类,派生类的作用域是嵌套在基类中的。
      class base{
      private:
          int x;
      public:
          virtual void mf1()=0;
          virtual void mf1(int );
          virtual void mf2();
          void mf3();
          void mf3(double);
          ... 
      };
      class derived :public base{
      public:
          virtual void mf1();
          void mf3();
          void mf4();
      };
      int main(){
          derived d;
          int x;
          d.mf1();//true    调用derived::mf1
          d.mf1(x);//wrong  derived::mf1遮掩了base::mf1(int)
          d.mf2();//true
          d.mf3();//true
          d.mf3(x);//wrong derived::mf3遮掩了base::mf3(double)
      }
      //这里面的是名称遮掩规则,不考虑参数的类型,而是直接考虑名称,这里直接相关的东西是作用域这个东西。
      //解决办法:在main函数中,明确的使用using声明表达式去显示的调用自己享用的函数即可。
    •   在public继承下,derived类的名称会遮掩base class内的名称。在public继承下面从来没有人希望如此
    •   我们可以使用using声明表达式去显示的调用想调用的函数或者变量等。


  • 区分接口继承和实现继承
    •   一个基类有三个函数:一个pure virtual,一个 impure virtual,一个non virtual。
      •   声明一个pure virtual函数的目的是让片派生类只是继承函数接口
      •   声明一个impure virtual函数的目的是让派生类继承该函数的接口给和缺省实现:继承该非纯虚函数,既可以自己实现这个函数,也可以缺省的调用父类的这个函数而不去重写派生类中的这个函数
      •   声明一个non virtual函数的目的是为了令派生类继承函数的接口给及一份强制性实现。

    •   接口继承和实现继承不同,在public继承下,派生类总是继承base class的接口
    •   pure virtual函数只是具体制定接口继承,impure virtual函数具体指定接口继承和缺省的实现继承,non virtual函数具体制定接口继承以及强制性实现继承



  • 绝对不重新定义继承而来的non-virtual
    •   non-virtual是静态绑定的,virtual是动态绑定的。
      class b{
      public:
          void mf();
      };
      class d:public b{
          void mf();
      };
      int main(){
          d x;
          b* pb=&x;
          pb->mf();
          
          d* pd=&x;
          pd->mf();
      }
      //其中b的mf函数和d的函数mf都是静态绑定的,non-virtual函数。但是如果mf是一个virtual函数的话,那么virtual是动态绑定的,mf是个virtual函数,不论通过pb还是pd
      //调用mf,都会是调用的pd::mf()。



  • 绝不重新定义继承而来的缺省参数值
    •   virtual是动态绑定的(调用一个virtual函数时,究竟调用哪一个实现代码,由调用的那个独享的动态类型),non-virtual是静态绑定的,缺省参数值也是静态绑定的。
      class shape{
      public:
          enum shapecolor{red,green,blue};
          virtual void draw(shapecolor color = red)const=0;//带有默认参数的virtual函数绝对不重新定义该默认参数
          ...
      };
      class rectangle:public shape{
      public:
          virtual void draw(shapecolor color = red)const;//这样就代码重复了
      };
      
      //修改的版本
      class shape{
      public:
          enum shapecolor{red,green,blue};
          void draw(shapecolor color = red)const{
              dodraw(color);
          }
          ...
      private:
          virtual void dodraw(shapecolor color)cosnt = 0;
      };
      class rectangle:public shape{
      public:
          ... ;
      private:
          virtual void dodraw(shapecolor color)const;//这里不需要指定默认参数值
      };
      //这里就是利用了non-virtual函数永远不会被派生类重写,这样就能保证默认参数值不会被修改和重新定义了。




  • 通过复合塑模出has-a或者根据某物实现出
    •   复合:类型之间的一种关系,当某种类型的对象内含它种类型的对象。它意味着has-a或者是is-implement-in-terms-of(根据某物实现出)。当复合发生在应用域内的对象的时候表现出has-a关系,发生在实现域表现is-implement-in-terms-of。
      •   应用域:人,汽车,动物,这些属于应用域。
      •   实现域:像缓冲器,查找树,互斥器这种东西属于实现域。

    •   复用和继承完全不同的,复用不用去继承。



  • 明智而审慎的使用private继承
    •   private意味着;private的派生对象系统是不会自动的将它变成一个base类对象的。从private base class中继承而来的所有成员在derived class都会变成paivate属性。
    •   private意味着:根据某物实现出is-implement-in-terms-of。如果D以private形式继承B,意思是D对象根据B对象实现而得。
    •   由于复合和private继承貌似有重合的部分,但是我们尽可能的使用复合,在必要时才使用private继承。




  • 明智而审慎的使用多重继承
    •   当多重继承出现的时候,程序有可能从一个以上的base class继承相同名称的函数或者其他东西。会产生较多的起义。
    •   多重继承比单一继承复杂,他可能导致新的起义性,以及对virtual继承的需要。
    •   virtual继承会增加大小,速度,初始化复杂度等等成本。如果virtual base class不带任何数据,将是最具实用价值的情况。
    •   多重继承的确有正当用途。其中一个情节设计public继承某个interface class和private继承某个协助实现的class 的两辆组合。

  

原文地址:https://www.cnblogs.com/Kobe10/p/5743701.html