OOP面向对象编程

GP泛型编程(generic programming)

两者的主要区别就是OOP将数据和对数据的操作放在一起,

GP就是将数据和操作独立开来

 

GP:   数据就是container进行存储,操作就是函数,也就是最数据操作的算法,container和algorithn都可以各自闭门造车,之间通过iteration联通就可以了

比如说sort

sort(begin,end,cmp)

algorithm通过iteration操作确定范围,并通过iteration来取出contain中的数据

大家可以看一下钱的stl六大部件中的那张六大部件的关系图

 

 

为什么list不能使用sort(没有内置sort)

list《int》ls

ls.sort()错误

sort内部的源码中cmp那里有first+(last-first)/2

也就是对迭代器不定数量的偏移,如果想要这样操作,那么操作的数据在内存中的位置一定是连续的

但是list存储的链表吗,链表每一个元素所占的地址不是连续的,我们在操作list的时候可以通过迭代器一个一个的进行偏移,但是不能偏移多个,因为地址不是连续,所以内部也就不能使用sort

 

random access iterator

所有algorithm,其内部设计元素本身的操作,无非就是比大小

 8**************************************************************************************************

模板

一:模板有函数模板和类模板

类模板很常见了,我们使用的stl都需要使用类模板,类模板需要《type》去指定类型,这是为了告诉编译器类型,否则编译器没有线索去判断什么类型

oop &&GP  模板 ---> 特化和偏特化_数据

上面这张图是函数函数min,首先我们定义了stone的两个对象,之后我们使用min模板函数,这个时候编译器做了一件非常棒的事情,就是编译器对函数模板进行了实参类型的推导,编译器会看他的参数r1,找到上一行,发现是stone类型的,如果min中的T就是stone类型了,之后min要进行操作,编译器进入min后走到<的时候,首先他作用于<左边的参数,并到T类型中查看时候与<的重载,发现在stone类中确实有重载,编译器于是走到operator中,发现是按到weight比较的,于是执行

 二:成员模板

 不重要

 

 


类模板又有特化,和偏特化,偏特化又有个数上的偏和范围上的偏

模板特化

有时为了需要,针对特定的类型,需要对模板进行特化,也就是所谓的特殊处理。比如有以下的一段代码:

 

 

#include <iostream>
using namespace std;
 
template <class T>
class TClass
{
public:
     bool Equal(const T& arg, const T& arg1);
};
 
template <class T>
bool TClass<T>::Equal(const T& arg, const T& arg1)
{
     return (arg == arg1);
}
 
int main()
{
     TClass<int> obj;
     cout<<obj.Equal(2, 2)<<endl;
     cout<<obj.Equal(2, 4)<<endl;
}

类里面就包括一个Equal方法,用来比较两个参数是否相等;上面的代码运行没有任何问题;但是,你有没有想过,在实际开发中是万万不能这样写的,对于float类型或者double的参数,绝对不能直接使用“==”符号进行判断。所以,对于float或者double类型,我们需要进行特殊处理,处理如下:

 

 1 #include <iostream>
 2 using namespace std;
 3  
 4 template <class T>
 5 class Compare
 6 {
 7 public:
 8      bool IsEqual(const T& arg, const T& arg1);
 9 };
10  
11 // 已经不具有template的意思了,已经明确为float了
12 template <>
13 class Compare<float>
14 {
15 public:
16      bool IsEqual(const float& arg, const float& arg1);
17 };
18  
19 // 已经不具有template的意思了,已经明确为double了
20 template <>
21 class Compare<double>
22 {
23 public:
24      bool IsEqual(const double& arg, const double& arg1);
25 };
26  
27 template <class T>
28 bool Compare<T>::IsEqual(const T& arg, const T& arg1)
29 {
30      cout<<"Call Compare<T>::IsEqual"<<endl;
31      return (arg == arg1);
32 }
33  
34 bool Compare<float>::IsEqual(const float& arg, const float& arg1)
35 {
36      cout<<"Call Compare<float>::IsEqual"<<endl;
37      return (abs(arg - arg1) < 10e-3);
38 }
39  
40 bool Compare<double>::IsEqual(const double& arg, const double& arg1)
41 {
42      cout<<"Call Compare<double>::IsEqual"<<endl;
43      return (abs(arg - arg1) < 10e-6);
44 }
45  
46 int main()
47 {
48      Compare<int> obj;
49      Compare<float> obj1;
50      Compare<double> obj2;
51      cout<<obj.IsEqual(2, 2)<<endl;
52      cout<<obj1.IsEqual(2.003, 2.002)<<endl;
53      cout<<obj2.IsEqual(3.000002, 3.0000021)<<endl;
54 }

注意一个问题就是

20 template <>
21 class Compare<double>
22 {
23 public:
24      bool IsEqual(const double& arg, const double& arg1);
25 };


注意对于特化一定要是带有空的<>的,注意格式的问题,和正常的模板类有很大的不用结构问题

模板偏特化

上面对模板的特化进行了总结。那模板的偏特化呢?所谓的偏特化是指提供另一份template定义式,而其本身仍为templatized;也就是说,针对template参数更进一步的条件限制所设计出来的一个特化版本。这种偏特化的应用在STL中是随处可见的。比如:


template <class _Iterator>
struct iterator_traits
{
     typedef typename _Iterator::iterator_category iterator_category;
     typedef typename _Iterator::value_type        value_type;
     typedef typename _Iterator::difference_type   difference_type;
     typedef typename _Iterator::pointer           pointer;
     typedef typename _Iterator::reference         reference;
};
 
// specialize for _Tp*
template <class _Tp>
struct iterator_traits<_Tp*> 
{
     typedef random_access_iterator_tag iterator_category;
     typedef _Tp                         value_type;
     typedef ptrdiff_t                   difference_type;
     typedef _Tp*                        pointer;
     typedef _Tp&                        reference;
};
 
// specialize for const _Tp*
template <class _Tp>
struct iterator_traits<const _Tp*> 
{
     typedef random_access_iterator_tag iterator_category;
     typedef _Tp                         value_type;
     typedef ptrdiff_t                   difference_type;
     typedef const _Tp*                  pointer;
     typedef const _Tp&                  reference;
};

 

看了了么?这就是模板偏特化,与模板特化的区别在于,模板特化以后,实际上其本身已经不是templatized,而偏
特化,仍然带有templatized。也就是说不为空的<>,<>内部仍然指明是什么具体类型,我们来看一个实际的例子:

 

#include <iostream>
using namespace std;
 
// 一般化设计
template <class T, class T1>
class TestClass
{
public:
     TestClass()
     {
          cout<<"T, T1"<<endl;
     }
};
 
// 针对普通指针的偏特化设计
template <class T, class T1>
class TestClass<T*, T1*>
{
public:
     TestClass()
     {
          cout<<"T*, T1*"<<endl;
     }
};
 
// 针对const指针的偏特化设计
template <class T, class T1>
class TestClass<const T*, T1*>
{
public:
     TestClass()
     {
          cout<<"const T*, T1*"<<endl;
     }
};
 
int main()
{
     TestClass<int, char> obj;
     TestClass<int *, char *> obj1;
     TestClass<const int *, char *> obj2;
 
     return 0;
}

 

特化与偏特化的调用顺序

对于模板、模板的特化和模板的偏特化都存在的情况下,编译器在编译阶段进行匹配时,是如何抉择的呢?从哲学的角度来说,应该先照顾最特殊的,然后才是次特殊的,最后才是最普通的。编译器进行抉择也是尊从的这个道理