CPP设计思维新模式

CPP设计思维新模式

===

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

  2. 特化

    1
    2
    3
    4

    template <class T,class U>

    class Tt{};

    特化其中一个参数

    1
    2
    3
    template <class U> 

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

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    class A 

    {

    private:

    A(){ }

    ~A(){ }



    public:

    void Instance()//类A的内部的一个函数

    {

    A a;

    }

    };

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    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();

    或者如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     class A 

    {

    private:

    A(){ }

    ~A(){ }



    public:

    Static A* Instance()//类A的内部的一个函数

    {

    Return new A;

    }

    };
    A* pA = A::Instance();

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

  3. 智能指针

    1. 拷贝、赋值是摧毁式拷贝
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      Template<typename T> 

      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;

      };
  1. 取址操作符

    其目的是为了smartpoint 能够跟 dumb pointers 尽可能相似

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    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为用户自定义类型

    1
    2
    3
    operator TYPE() 
    {
    }

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Class c 

    {

    Operator bool()


    Return true;


    };

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Template<typename T> 

    Class SmartPtr

    {

    public:

    operator T*()

    {

    Return ptr;

    }

    //…

    private:

    T* ptr;

    };

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    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
  2. 相等性 不等性
    最好的方法,完整、可靠的方法:采用完全一致的做法,分别为每个操作法定义一份重载:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    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;

    }


    };

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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 那么下面的代码还存在歧义性:

1
2
3
4
5
6
7
8
9
SmartPtr<Base> sp; 

Derived *p;

If(sp==p) //以上重载方法,存在的歧义:(Base*)sp == (Base*)p and operator == (sp,(Base*)p)

{

}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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;

}

…其他的类似



};

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

1
2
3
4
SmartPtr<Apple> sp1; 

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Template <typename T> 

Class SmartPtr

{

public:

… 同上……

template<typename T>

bool operator == (const SmartPtr<U> &rhs) const

{

return ptr == rhs.ptr;

}

…其他的操作符于此类似….

};

坚持原创技术分享,您的支持奖鼓励我继续创作!