模板的简单介绍
C++中模板是为了能够使得函数或者类实现范型编程的目的, 同时C++模板的出现是为了避免代码的冗余
举个例子
void Swap(int& a, int& b)
{int tmp = a;b = a;a = b;
}
void Swap(char& a, char& b)
{char tmp = a;b = a;a = b;
}
上面的函数除了类型不同以外, 其他都可以看成是完全形同的, 但是由于代码不支持范型编程, 所以我们就必须将不同的类型都实现一遍.为了避免这种代码冗余, 于是就出现的模板.
其中模板可以分为函数模板和类模板
函数模板
template <class T>
void swap(T& a, T& b)
{T tmp = a;a = b;b = a;
}
void TestSwap()
{swap(1, 2);
}
编译器在执行上述代码的时候就会根据实参的不同自动推演出类型, 然后将自己的类型传给对应的 T, 此时编译器也就直到了参数的类型
注意 编译器在进行类型实例化的时候如果有现成的类型符合自己(不用经过推演), 那么编译器就会去调用现成的函数, 当没有现成的函数给自己调用的时候, 但是有模板函数, 此时编译器就会是使用模板生成一份
模板类
template <class T>
class Vector
{
public:Vector();~Vector();Vector(const Vector <T>& v);Vector& operator = (const Vector <T>& v);void Reserve(size_t size);void ReSize(size_t size, const T& value = T());const T& operator [] (size_t pos) const;void Insert(size_t pos, const T& x);void PushFront(const T& x);void PushBack(const T& x);void Erase(size_t pos);size_t Capacity();bool Empty();size_t Size();void PopBack();void PopFront();
protected:void Expand(size_t size);
protected:T* _start;T* _finish;T* _endofstorage;
};
上面代码就是通过模板类实现Vector的各种操作. 在使用模板类的时候, 当模板类成员函数定义在类体外的时候, 此时应该注意, 书写格式和原来的就会有所不同, 用上面Vector这个模板类来做个比方吧
template <class T>
Vector& Vector <T>::operator = (const Vector <T>& v)
{...
}
小知识点总结
模板相关
模板在经过实例化之后才会生成指令. 编译器在进行编译的时候只会对模板的外壳进行语法检查不会对它的内容进行检查
Vector增容做了哪些事情
Vector在增容的时候它会做两件事情, 第一件事情就是进行动态内存开辟. 当开辟完内存之后, 它会看一下此时的类型是自定义类型还是内置类型, 如果是自定义类型就将原来空间上的内容直接memcpy拷贝给新开辟的这片空间, 然后释放原来的内存空间. 当发现此时的类型是一个自定义类型的时候, 此时就要进行深拷贝, 具体做法就是申请一片新的空间, 然后利用循环将原来空间中的值重新复制给新的这片空间, 最后释放原来的空间
自动定义类型之为什么需要深拷贝
加入此时的类型是一个sring类型, 当进行扩容的时候编译器会给其分配一个新的空间, 此时当我们定义出来一个对象的时候, 如果出了作用域对象就要析构,当进行析构的时候, 加入我们只是进行了简单的memcpy此时新开辟的空间中的string指向原来的空间, 但是当我们memcpy完之后就会对其进行释放, 然而此时由于对象出了作用域就要进行析构, 此时就会出现对一个野指针进行销毁, 当然会出错