CPP设计思维新模式 - leeqx/leeqx.github.io GitHub Wiki

CPP设计思维新模式

===

  1. 系统架构的一个主要基本原则是以设计实现某些原则

  2. 特化

  template <class T,class U> 
  
  class Tt{}; 

特化其中一个参数

  template <class U> 
  
  class Tt<widget w>{}; 
  1. 关于protected 析构

    采用proected 权限的析构目的是使得当删除基类指针时(该指针指向了派生类对象),
    使其不调用派生类的析构(因为权限问题,无法访问派生类的析构方法);
    这样做如果该类中不存在其他virtual类型的方法,将避免增加vptr 导致性能得到降低。
    当然如果希望delete基类指针时能够调用派生类的析构,那么基类的析构需要声明为
    virtual,同时这不可避免的导致内存性能下降问题。

  2. 关于private、protected 的构造方法

    对于这两种权限的构造方法,由于无法在外部调用所以将导致在类外无法构建对象。
    但是protected在其子类中可以构造。所以如果存在场景只允许其派生类构造对象那么
    可以将构造方法声明为protected。如果是private 那么只能在该类内部使用。例子:

  class A 
  
  { 
  
  private: 
  
  A(){  } 
  
  ~A(){ } 
  
   
  
  public: 
  
  void Instance()//类A的内部的一个函数 
  
  { 
  
  A a; 
  
  } 
  
  }; 

上面的代码是能通过编译的。上面代码里的Instance函数就是类A的内部的一个函数。
Instance函数体里就构建了一个A的对象。
但是,这个Instance函数还是不能够被外面调用的。为什么呢?
如果要调用Instance函数,必须有一个对象被构造出来。但是构造函数被声明为private
的了。外部不能直接构造一个对象出来。

  A aObj; // 编译通不过 
  aObj.Instance(); 

但是,如果Instance是一个static静态函数的话,就可以不需要通过一个对象,而可以直接被调用。如下:

  class A 
  
  { 
  
  private: 
  
  A():data(10){ cout << "A" << endl; } 
  
  ~A(){ cout << "~A" << endl; } 
  
   
  
  public: 
  
  static A& Instance() 
  
  { 
  
  static A a; 
  
  return a; 
  
  } 
  
   
  
  void Print() 
  
  { 
  
  cout << data << endl; 
  
  } 
  private: 
  int data; 
  
  }; 
  A& ra = A::Instance(); 
  
  ra.Print(); 

或者如下:

  class A 
  
  { 
  
  private: 
  
  A(){  } 
  
  ~A(){ } 
  
   
  
  public: 
  
  Static A* Instance()//类A的内部的一个函数 
  
  { 
  
  Return new A; 
  
  } 
  
  }; 
 A* pA = A::Instance(); 

同时采用这种技术,可以将operator= 声明为private 但是没有具体实现,
这样子可以禁止一个类的外部用户对这个类的对象进行复制动作。

  1. 智能指针

  2. 拷贝、赋值是摧毁式拷贝
    ```c Template

    class SmartPtr

{ 

public: 

   SmartPtr(SmartPtr &src) 

{ 

  this->ptr = src.ptr; 

  src.ptr = NULL;// 摧毁 

} 

    SmartPtr& operator=(SmartPtr &src) 

{ 

If(this != &src) 

{ 

This->ptr = src.ptr; 

Src.ptr = NULL; // 摧毁 

} 

 

} 

private: 

T* ptr; 

};  
 
  0. 取址操作符 

     其目的是为了smartpoint 能够跟 dumb pointers 尽可能相似 
    ```c
    Template<typename T> 
    
    Class SmartPtr 
    
    { 
    
       public: 
    
     T** operator&() 
    
    { 
    
    Return &ptr; 
    
    } 
    
    Private: 
    
    T* ptr; 
    
    }; 
    
     
    // 有了取址操作符之后下面的运作就会成立: 
    
    Void Fun(Widget** pW); 
    
    SmartPtr<Widget> spW(new Widget()); 
    
    Fun(&spW); 
但是不建议重载operator& 
  1. 隐式转换 至原始指针

用户自定义转换符重载,该符号重载不能写明返回类型,其返回采用operator 后面的类型,
格式如下:TYPE为用户自定义类型

 operator TYPE() 
  { 
  } 

例如:

  Class c 
  
  { 
  
  Operator bool() 
  
  { 
  Return  true; 
  } 
  
  }; 

为了能够使得我们自定义的数据自行转换,我们需要重载转换符。

  Template<typename T> 
  
  Class SmartPtr 
  
  { 
  
    public: 
  
      operator T*() 
  
     { 
  
  Return ptr; 
  
     } 
  
     //… 
  
     private: 
  
          T* ptr; 
  
  }; 

有了该转换之后,下面的代码就可以编译:

  Void  Fun(Widget  *pw); 
  SmartPtr<Widget> sp(new Widget()); 
  Fun(sp); 

但是与此同时也引入了新问题:外部直接对智能指针进行delete操作,那么我们的职能指针久形同虚设
所以为了避免这个问题,我们采用歧义性,使得对delete的操作编译无法通过,便可达到目的:

  Template<typename T> 
  
  Class SmartPtr 
  
  { 
  
     public: 
  
  Operator T*() 
  
  {  
  
     return ptr; 
  
  } 
  
  Operator void*() 
  
  { 
  
  Return ptr; 
  
       } 
  … 
  
  Private: 
  
     T* ptr; 
  
  }; 
  
  SmartPtr<Widget> sp(new Widget()); 
  Delete sp; //compile error 
  1. 相等性 不等性
    最好的方法,完整、可靠的方法:采用完全一致的做法,分别为每个操作法定义一份重载:
  Template<typename T> 
  
  Class SmartPtr 
  
  { 
  
  Public: 
  
   bool operator !() const // Enable "if (!sp) …" 
  
  { 
  
       return ptr== NULL; 
  
  } 
  
   
  
  Inline friend bool operator == (const SmartPtr<T> &lhr, const T* rhs) 
  
  { 
  
      return lhs.ptr == rhs; 
  
   } 
  
   
  
  Inline friend bool operator == ( const T* lhs, const SmartPtr<T> &rhs) 
  
  { 
  
      return lhs == rhs.ptr; 
  
  } 
  
   
  
  Inline friend bool operator != (const SmartPtr<T> &lhr,const T* rhs) 
  
  { 
  
     return lhs.ptr != rhs; 
  
  } 
  Inline friend bool operator != (const T* lhs,const SmartPtr<T> & rhs) 
  
  { 
  Return lhs != rhs.ptr; 
  
  } 
  … 
  
  }; 

下面的代码就可以运作了:

  SmartPtr <Widget> sp1,sp2; 
  Widget *p; 
  
  If(sp1) 
  ..
  
  If(!sp1) 
  .. 
  
  If(sp1==NULL) 
  
  .. 
  
  If (sp1==sp2) 
  
  … 
  
  If(sp1==p) 
  
  … 
  
  If(p==sp1) 

但至此还还不完美,如果提供一个“转型之ptr 型别”的自动转换式,还是存在歧义
。假设一个Base class 以及一个从base 继承而来的Derive class 那么下面的代码还存在歧义性:

  SmartPtr<Base> sp; 
  
  Derived *p; 
  
  If(sp==p) //以上重载方法,存在的歧义:(Base*)sp == (Base*)p   and operator == (sp,(Base*)p) 
  
  { 
  
  } 

为此我们需要的对上面重载的比较方法添加template版本

  Template<typename T> 
  
  Class SmartPtr 
  
  { 
  
   public: 
  
          …//同上(非template版本) 
  
  template<typename U> 
  
  inline friend bool operator == (const SmartPtr<U> &lhr,const U* rhs) 
  
  { 
  
  Return lhs.ptr == rhs; 
  
  } 
  
  Template <typename U> 
  
   inline friend bool operator == (const U*lhs,const SmartPtr<U>&rhs) 
  
  { 
  
  Return lhs == rhs.ptr; 
  
  } 
  
  …其他的类似 
  
   
  
  }; 

但是至此依然不完美: 因为:

  SmartPtr<Apple> sp1; 
  
  SmartPtr <Oragne>sp2; 
  If( sp1==sp2)   //存在歧义 

为了消除该歧义,我们还要:

  Template <typename T> 
  
  Class SmartPtr 
  
  { 
  
    public: 
  
          … 同上…… 
  
    template<typename T> 
  
   bool operator == (const SmartPtr<U> &rhs) const 
  
  { 
  
    return ptr == rhs.ptr; 
  
  } 
  
  …其他的操作符于此类似…. 
  
  }; 
⚠️ **GitHub.com Fallback** ⚠️