OOP(面向对象编程)和GP(泛型编程)
- OOP:将methods和datas关联到一起(通俗点就是方法和成员变量放到一个类中实现),通过继承的方式,
利用虚函数表(virtual)来实现运行时类型的判定,也叫"动态多态",由于运行过程中需根据类型去检索虚函数
表,因此效率相对较低。- GP:泛型编程,也被称为"静态多态",多种数据类型在同一种算法或者结构上皆可操作,其效率与针对某特定数
据类型而设计的算法或者结构相同,具体数据类型在编译期确定,编译器承担更多,代码执行效率高。在STL中
利用GP将methods和datas实现了分而治之
而C++STL库的整个实现采用的就是GP(GenericProgramming),而不是OOP(ObjectOrientedProgramming)。而GOF设计模式采用的就是继承关系实现的,因此,相对来讲,C++STL的实现效率会相对较高,而且也更有利于维护。
类模板
template <typename T>
class MyClass {
public:
MyClass(T r = 0, T i = 0):re(r), im(i){}
MyClass& operator += (const MyClass&);
T real()const {return re;}
T imag()const {return im;}
private:
T re, im;
};
MyClass<doouble>c2 (2.5, 1.5);
MyClass<int>c2(2, 6);
函数模板
template<class T>
inile
const T& min(const T& a, const T& b)
{
return b < a ? b : a
}
成员模板
class MyArray {
public:
template <typename T>
void set(int index, T value) {
data[index] = value;
}
template <typename T>
T get(int index) {
return data[index];
}
private:
int size;
T* data;
};
int main() {
MyArray intArray(10);
MyArray doubleArray(5);
intArray.set(0, 1);
doubleArray.set(0, 3.14);
int intValue = intArray.get<int>(0);
double doubleValue = doubleArray.get<double>(0);
}
泛化
- 泛化是最基本的模板编程技术,它通过定义一个通用的模板来适用于不同的数据类型。
- 泛化模板的定义通常包含一个或多个类型参数,用于指定可以适用的类型。
- 泛化模板可以用于定义类模板或函数模板。
template <typename T>
T myMax(T a, T b) {
return (a > b) ? a : b;
}
int main() {
int a = 10, b = 20;
double c = 1.23, d = 4.56;
int max_int = myMax<int>(a, b);
double max_double = myMax<double>(c, d);
return 0;
}
特化
- 特化是一种在泛化模板基础上定义特定类型的模板,它可以覆盖泛化模板的默认实现。
- 特化模板的定义通常包含一个或多个类型参数,用于指定特化的类型。
- 特化模板可以用于定义类模板或函数模板。
template <class Key>struce hash{ };
'特化'
template<>
struce hash<char>{
size_t operator()(char x) const {return x;}
}
struce hash<int>{
size_t operator()(char x) const {return x;}
}
'特化'
template <>
const char* myMax<const char*>(const char* a, const char* b) {
return (strcmp(a, b) > 0) ? a : b;
}
偏特化
- 偏特化是一种在泛化模板基础上定义部分类型的模板,它可以针对某些类型进行特定的实现。
- 偏特化模板的定义通常包含一个或多个类型参数和一个或多个非类型参数,用于指定偏特化的类型。
- 偏特化模板只能用于定义类模板。
- 比如模板当中有两个参数,而偏特化是将一个参数进行绑定,另一个参数根据传进来的类型,来进行判断。
template<class T, class Alloc = alloc>
class vector{...;}
'偏特化'
template<class Alloc>
class vector<bool, Alloc>{...;}
template<typename Iterator> //萃取前
typename Iterator::value_type func(Iterator iter) {
return *iter;
}
//通过 iterator_traits 作⽤后的版本
template<typename Iterator> //萃取后
typename iterator_traits<Iterator>::value_type func(Iterator iter) {
return *iter;
}
为什么还要增加 iterator_traits这⼀层封装,岂不是多此⼀举?
- 回想萃取之前的版本有什么缺陷:不⽀持原⽣指针。⽽通过萃取机的封装,我们可以通过类模板的特化来⽀持原⽣ 指针的版本!如此⼀来,⽆论是智能指针,还是原⽣指针,iterator_traits::value_type 都能起作⽤,这就解决了前 ⾯的问题。
#include
template <class T>
struct MyIter {
typedef T value_type; // 内嵌型别声明
T* ptr;
MyIter(T* p = 0) : ptr(p) {}
T& operator*() const { return *ptr; }
};
// class type
template <class T>
struct my_iterator_traits {
typedef typename T::value_type value_type;
};
// 偏特化 1
template <class T>
struct my_iterator_traits<T*> {
typedef T value_type;
};
// 偏特化 2
template <class T>
struct my_iterator_traits<const T*> {
typedef T value_type;
};
// 首先询问 iterator_traits::value_type,如果传递的 I 为指针,则进入特化版本,iterator_traits
template <class I>
typename my_iterator_traits<I>::value_type Func(I ite) {
std::cout << "normal version" << std::endl;
return *ite;
}
int main(int argc, const char *argv[]) {
MyIter<int> ite(new int(6));
std::cout << Func(ite)<<std::endl;//print=> 6
int *p = new int(7);
std::cout<<Func(p)<<std::endl;//print=> 7
const int k = 8;
std::cout<<Func(&k)<<std::endl;//print=> 8
}
'输出结果'
normal version
6
normal version
7
normal version
8
template<typename Category,
typename T,
typename Distance = ptrdiff_t,
typename Pointer = T*,
typename Reference = T&>
struct iterator //迭代器的定义
{
typedef Category iterator_category;
typedef T value_type;
typedef Distance difference_type;
typedef Pointer pointer;
typedef Reference reference;
};
迭代器萃取机设计如下:
tempalte<typename I>
struct iterator_traits {//特性萃取机,萃取迭代器特性
typedef typename I::iterator_category iterator_category;
typedef typename I::value_type value_type;
typedef typeanme I:difference_type difference_type;
typedef typename I::pointer pointer;
typedef typename I::reference reference;
};
//需要对型别为指针和 const 指针设计特化版本看
迭代器型别 iterator_category 对应的迭代器类别,这个类别会限制迭代器的操作和移动 特性。 除了原⽣指针以外,迭代器被分为五类:
__type_traits负责萃取型别的特性。
型别的特性有:trivial ctor, copy ctor,assignment,dtor以及non-trivial ctor, copy ctor,assignment,dtor,如果答案是不重要的,那我们在对型别进行构造,析构,拷贝,赋值等操作时就可以采用最有效的措施(例如不需要调用constructor,destructor),而是采用内存直接处理操作如 malloc(),nencpy()等。
调用函数的流程:
iterator_traits
被称为特性萃取机,萃取迭代器的型别,一共有5种:
type_traits
关注的是型别的特性,例如这个型别是否具备non-trivial defalt ctor(默认构造函数)、non-trivial copy ctor(拷贝构造函数)、non-trivial assignment operator(赋值运算符) 和non-trivial dtor(析构函数),如果答案是否定的,可以采取直接操作内存的方式提高效率,一般来说,type_traits支持以下5中类型的判断:
// ++i实现代码为——前置:
int& operator++(){
*this += 1;
return *this;
}
//i++实现代码为—后置:
int operator++(int){
int temp = *this;
++*this;
return temp;
}
容器 | 迭代器 |
---|---|
vector、deque | 随机访问迭代器 |
stack、queue、priority_queue | 无 |
list、(multi)set/map | 双向迭代器 |
unordered_(multi)set/map、forward_list | 前向迭代器 |
以vector为例:
插入元素:
删除元素: