(1)面向对象编程(OOP)与泛型编程(GP)之间的区别:
OOP试图将datas与methods关联在一起,为此在OOP中,将数据与操作放置在同一个类中,同时设定了类之间的继承关系。
GP则是将datas与methods分离。例如sort没有被定义为类内的成员函数,而是将其归入STL的算法中,作为一个全局函数存在。算法和容器之间利用迭代器进行关联。
采用GP编码:
<1>Containers和Algorithms彼此之间不存在交叉,两者可以单独进行开发,只需要利用Iterator进行沟通即可。
<2>Algorithms可以通过Iterators确定其操作范围,并且可以通过Iterators取用Container中的元素。
在上述例子中,可以看出两个max函数一个使用了编译器自带的<操作,而另一个使用仿函数comp自定义比较规则。对于所有Algorithms,其中最终涉及元素本身的操作,无非就是比较大小。由于上述函数利用了模板,因此应当注意所传入的类型T应当能够支持进行相对应的比较操作,否则则需要对比较操作运算符进行重载。
对于操作符重载应该注意:并不是所有的操作符都能够被重载。重载之后的操作符函数可以被作为一个全局函数,也可以被作为一个成员函数。
(2)模板
<1>类模板:注意其关键字template。其中的T类型不确定,在模板被使用时确定其具体类型。
<2>函数模板:其关键字template。在使用时,编译器会对函数模板进行实参推导,确定模板中T的具体类型。
<3>成员模板
(3)模板的特化
特化可以被分为全特化与偏特化。
<1>一个被泛化的模板为:
template
struct A{…..}
经过全特化后为:
template<>struct A{…..}
template<>struct A{…..}
<2>偏特化也被称为局部特化。
template
class vector{......};
实施偏特化后:
template
class vector{......};
上述偏特化为个数的偏特化。
template
struct A{…..};
能够接受任意类型的type。将其进行范围的偏特化,使其只能够接受固定类型的type。
template
struct A{…..};
template
struct A{…..};
(4)分配器allocators
分配器所分配内存是使用operator new()和malloc()函数完成容器所需要的内存的分配。
通过上图可以看出,通过分配器所分配的内存比实际所需要的内存数量要大,其中包括cookie等额外所分配的控件。所需要分配的控件越小,则其所额外分配的内存在总体内存中所占用的比例越大。本周课堂上所比较的几种编译器只是以::operator new和::operator delete完成allocate()和deallocate(),没有任何特殊的设计.。
可以利用allocator()完成临时对象的创建。
int* p = allocator().allocate(512,(int*)0);
其中必须指定所分配的内存的大小。同时在进行内存释放时:
allocator().deallocate(p,512);
释放内存时必须同时给出所分配的内存数目。
在G4.9所附带的标准库中,有许多extention allocators(附加类型的分配器)。
其中__pool_alloc就是G2.9中的alloc。
(5)List
list容器是一种双向的链表,因此其节点除了存放数据之外,还存在一个向前的指针和一个向后的指针。
template
struct __list_node{
typedef void* void_pointer;
void_pointer prev;
void_pointer next;
T data;
}
由此可知list容器的迭代器的结构如下:
template
struct __list_iterator{
typedef T value_type;
typedef Ptr pointer;
typedef Ref reference;
……
}
除了vector和array之外。其余容器的迭代器都应当是一个class,也就是一个智能指针。
迭代器的++++和----操作:
前++为:
self& operator++()
{
node= (link_type)((*node).next);
return *this;
}
后++为:
self operator++(int)
{
self tmp = *this; //记录原值
++*this; //进行操作
return tmp;//返回原值
}
本次编程作业中要求打印中间元素:
Index = (ListData.size()) / 2;
for(iList = ListData.begin(); iList != ListData.end();++++iList)
{
----Index;
if(Index == 0)
{
cout<< "中间元素为:" << *iList << endl ;
break;
}
}
使用++++能够得到正确的节点值,而++得到的是正确节点的前一个节点值。
(6)Traits
iterator需要遵循的原则
std::rotate(__first,__middle,__last,std::iterator_category(__first));
在上例中,rotate()需要知道iterators的三个associated types。
iterators必须有能力回答algorithms的提问。这样的提问在C++标准库开发过程中设计了五种:category:种类;difference_type;距离;value_type:值类型;reference;pointer。
如果iterator不是一个class,也就是说此时iterator是一个原生指针,这时的iterator被称为退化的。
Iterator Traits用以分离class iterators和non—class iterators。
(7)容器vector
Vector容器的容积以二倍增长的形式增长。
Vector容器的迭代器就是一个原生指针。
(8)容器array
Array在C++11后,被添加至容器中。定义一个array必须指定其长度,一旦定义,array无法自动变更容积。
(9)forward_list容器
作者:游在路上的鱼
链接:http://www.jianshu.com/p/2ad200d9a018
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
网友评论