CPP设计思维新模式
===
系统架构的一个主要基本原则是以设计实现某些原则
特化
1
2
3
4
template <class T,class U>
class Tt{};特化其中一个参数
1
2
3template <class U>
class Tt<widget w>{};
关于protected 析构
采用proected 权限的析构目的是使得当删除基类指针时(该指针指向了派生类对象),
使其不调用派生类的析构(因为权限问题,无法访问派生类的析构方法);
这样做如果该类中不存在其他virtual类型的方法,将避免增加vptr 导致性能得到降低。
当然如果希望delete基类指针时能够调用派生类的析构,那么基类的析构需要声明为
virtual,同时这不可避免的导致内存性能下降问题。关于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
23class A
{
private:
A(){ }
~A(){ }
public:
void Instance()//类A的内部的一个函数
{
A a;
}
};上面的代码是能通过编译的。上面代码里的Instance函数就是类A的内部的一个函数。
Instance函数体里就构建了一个A的对象。
但是,这个Instance函数还是不能够被外面调用的。为什么呢?
如果要调用Instance函数,必须有一个对象被构造出来。但是构造函数被声明为private
的了。外部不能直接构造一个对象出来。1
2A 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
40class 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
24class A
{
private:
A(){ }
~A(){ }
public:
Static A* Instance()//类A的内部的一个函数
{
Return new A;
}
};
A* pA = A::Instance();同时采用这种技术,可以将operator= 声明为private 但是没有具体实现,
这样子可以禁止一个类的外部用户对这个类的对象进行复制动作。智能指针
- 拷贝、赋值是摧毁式拷贝
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
41Template<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;
};
- 拷贝、赋值是摧毁式拷贝
取址操作符
其目的是为了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
30Template<typename T>
Class SmartPtr
{
public:
T** operator&()
{
Return &ptr;
}
Private:
T* ptr;
};
// 有了取址操作符之后下面的运作就会成立:
Void Fun(Widget** pW);
SmartPtr<Widget> spW(new Widget());
Fun(&spW);但是不建议重载operator&
隐式转换 至原始指针
用户自定义转换符重载,该符号重载不能写明返回类型,其返回采用operator 后面的类型,
格式如下:TYPE为用户自定义类型1
2
3operator TYPE()
{
}例如:
1
2
3
4
5
6
7
8
9
10
11Class 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
23Template<typename T>
Class SmartPtr
{
public:
operator T*()
{
Return ptr;
}
//…
private:
T* ptr;
};有了该转换之后,下面的代码就可以编译:
1
2
3Void 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
33Template<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
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
54Template<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
22SmartPtr <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
9SmartPtr<Base> sp;
Derived *p;
If(sp==p) //以上重载方法,存在的歧义:(Base*)sp == (Base*)p and operator == (sp,(Base*)p)
{
}
为此我们需要的对上面重载的比较方法添加template版本
1 | Template<typename T> |
但是至此依然不完美:
因为:
1
2
3
4SmartPtr<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
23Template <typename T>
Class SmartPtr
{
public:
… 同上……
template<typename T>
bool operator == (const SmartPtr<U> &rhs) const
{
return ptr == rhs.ptr;
}
…其他的操作符于此类似….
};