目录
模板的概念
模板就是建立通用的模具,大大提高复用性
C++提供两种模板机制:函数模板和类模板
函数模板针对仅参数类型不同的函数;
类模板针对仅数据成员和成员函数类型不同的类。
函数模板
-
template<typename T> 函数声明或定义
-
使用函数模板有两种方式:自动类型推导、显示指定类型
类模板
- 建立一个通用类,类中的成员 数据类型可以不具体制定,用一个虚拟的类型来代表。
- template<typename T> 类
类模板与函数模板区别主要有两点:
- 类模板没有自动类型推导的使用方式
- 类模板在模板参数列表中可以有默认参数
实验
一、模板函数(compare)
一般模板函数
#include "mainwindow.h"
#include<iostream>
#include <QApplication>
template <class Type>
int compare(const Type &v1,const Type &v2)
{
if(v1<v2)
return -1;
if(v1>v2)
return 1;
return 0;
}
int main(int argc, char *argv[])
{
const char *cp1="world",*cp2="hi";
int a=1,b=2;
compare(a,b);
compare(cp1,cp2);
return 0;
/*
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();*/
}
运行结果
特化模板函数
当函数模板需要对某些类型进行特化处理,称为函数模板的特化。
template<>
int compare<const char*>(const char * const &v1, const char * const &v2)
{
cout<<"specialization"<<endl;
return strcmp(v1,v2);
}
运行结果
同时,函数模版的特化,当函数调用发现有特化后的匹配函数时,会优先调用特化的函数,而不再通过函数模版来进行实例化。
二、模板类Queue或Stack
类模板example
#include <string>
#include<iostream>
using namespace std;
//类模板
template<class T1, class T2 = int>
class Person
{
public:
Person(T1 name, T2 age)
{
this->mName = name;
this->mAge = age;
}
void showPerson()
{
cout << "name: " << this->mName << " age: " << this->mAge << endl;
}
public:
T1 mName;
T2 mAge;
};
//1、类模板没有自动类型推导的使用方式
void test1()
{
Person <string ,int>p("xxd", 1000); //必须使用显示指定类型的方式,使用类模板
p.showPerson();
}
//2、类模板在模板参数列表中可以有默认参数
void test2()
{
Person <string> p("jmu", 999); //类模板中的模板参数列表 可以指定默认参数
p.showPerson();
}
int main() {
test1();
test2();
return 0;
}
类模板和函数模板语法相似,在声明模板template后面加类,此类称为类模板
运行结果
queue
- push():会将一个元素置入queue中;
- front():会返回queue内的第一个元素
- back():会返回queue中的最后一个元素
- pop():会移除queue内的第一个元素
queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
using namespace std;
template<class Type> class Queue; //先声明 Queue
template<class Type>
class QueueItem{
QueueItem(const Type &t):item(t),next(0){}
Type item;
QueueItem *next;
friend class Queue<Type>;//友元函数 访问
friend ostream& operator<<(ostream& os,const Queue<Type> &q); //运算符重载
QueueItem<Type>* operator++(){
return next;
}
Type & operator*(){
return item;
}
};
template<class Type>
class Queue{
public:
//定义构造器
Queue():head(0),tail(0){}
Queue(const Queue& q):head(),tail(){
copy_items(q);
}
template<class It>
Queue(It beg,It end):head(0),tail(0){
copy_items(beg,end);
}
template<class It> void assign(It beg,It end);
Queue& operator=(const Queue&);
//析构函数
~Queue(){destory();}
Type& front(){return head->item;}
const Type& front() const {return head->item;}
void push(const Type &);
void pop();
bool empty() const {
return head==0;
}
friend ostream& operator<<(ostream& os,const Queue<Type> &q){
os<<"< ";
QueueItem<Type> *p;
for(p=q.head;p;p=p->next){
os<<p->item<<" ";
}
os <<">";
return os;
}
const QueueItem<Type> *Head() const{return head;}
const QueueItem<Type> *End() const{return (tail==NULL)?NULL:tail->next ;}
private:
QueueItem<Type> *head;
QueueItem<Type> *tail;
void destory();
void copy_items(const Queue &);
template<class It> void copy_items(It beg,It end);
};
//成员模板函数
template<class Type>
void Queue<Type>::destory(){
while(!empty()){
pop();
}
}
//移除第一个元素
template<class Type>
void Queue<Type>::pop(){
QueueItem<Type >* p=head;//赋值头指针
head=head->next; //指向下一个指针
delete p;
}
//在尾部添加一个新的元素
template <class Type>
void Queue<Type >::push(const Type& val){
QueueItem<Type> *pt =new QueueItem<Type>(val);
if(empty()){
head=tail=pt;
}
else{
tail->next=pt;
tail=pt;
}
}
//模板成员函数特化
template<>
void Queue<const char*>::push(const char * const &val);
template<>
void Queue<const char*>::pop();
template<class Type>
void Queue<Type>::copy_items(const Queue &orig){
for(QueueItem<Type> *pt = orig.head;pt;pt=pt->next){
push(pt->item);
}
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(const Queue& q)
{
destory();
copy_items(q);
}
template<class Type> template<class It> void Queue<Type>::assign(It beg, It end)
{
destory();
copy_items(beg,end);
}
template<class Type> template<class It> void Queue<Type>::copy_items(It beg,It end)
{
while(beg!=end){
push(*beg);
++beg;
}
}
template<class Type>
int compare(const Type& v1, const Type& v2)
{
if(v1<v2) return -1;
if(v1>v2) return 1;
return 0;
}
template<>
int compare<const char*>(const char * const &v1, const char * const &v2);
#endif // QUEUE_H
类模板的特化
当类模板内需要对某些类型进行特别处理时,使用类模板的特化。
模板成员函数特化
实现模板类Queue中的成员函数push()
和pop()
方法的特化版本,使其能够实现字符串的入队和出队操作。
#include "Queue.h"
#include <iostream>
#include <vector>
#include <string.h>
using namespace std;
template <>
void Queue<const char*>::push( const char * const & str)
{
char * pVal = new char[strlen(str)+1];
strcpy(pVal,str);
QueueItem<const char*> * p = new QueueItem<const char*>(pVal);
if(empty())
{
head = tail = p;
}
else {
tail->next = p;
tail = p;
}
}
template<>
void Queue<const char* >::pop()
{
if(empty())
{
return;
}
QueueItem<const char*> * p = head;
head = head->next;
delete []p->item;
delete p;
}
运行结果
三、模板类AutoPtr
智能指针
C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。程序员自己管理堆内存可以提高了程序的效率,但是整体来说堆内存的管理是麻烦的,所以引入了智能指针的概念,方便管理堆内存。使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存。
测试
#include <iostream>
#include <memory>
using namespace std;
class Test
{
public:
Test(int param = 0) //调用时,可以指定是第几个对象。默认第0个
{
num = param;
cout << "Simple:" << num << endl;
}
~Test() //析构时会指出第几个对象被析构。
{
cout << "~Simple:" << num << endl;
}
void PrintSomething() //输出附加的字符串方法。
{
cout << "PrintSomething:" << info_extend.c_str() << endl;
}
int num; //代表这个对象的序号。
string info_extend; //附加的字符串。
};
void TestAutoPtr1()
{
auto_ptr<Test> my_auto (new Test(1)); //绑定一个Test类的新建对象
if(my_auto.get()) //get函数用来显式返回它拥有的对象指针,此处判非空
{
my_auto->PrintSomething();
my_auto.get()->info_extend = "Addition"; //对类内成员进行操作
my_auto->PrintSomething(); //看是否成功操作
(*my_auto).info_extend += " other"; //实验解引用操作
mt_auto->PrintSomething();
}
}
测试结果
最后函数结束后,在调用析构函数的同时auto_ptr的析构函数也将Test类的对象delete掉
#ifndef AUTOPTR_H
#define AUTOPTR_H
template <class T>
class AutoPtr
{
public:
AutoPtr(T* pData);
AutoPtr(const AutoPtr<T>& h);
//调用析构函数
~AutoPtr();
AutoPtr<T>& operator=(const AutoPtr<T>& h);
void decrUser();
T* operator ->() {
return m_pData;
}
T& operator*() {
return *m_pData;
}
const T& operator *() const {
return *m_pData;
}
const T* operator -> () const {
return m_pData;
}
private:
T* m_pData;
int* m_nUser;
};
template < class T>
AutoPtr<T>::AutoPtr(T* pData)
{
m_pData = pData;
//初始化用户数为1
m_nUser = new int(1);
}
template < class T>
AutoPtr<T>::AutoPtr(const AutoPtr<T>& h) {
m_pData = h.m_pData;
m_nUser = h.m_nUser;
(*m_nUser)++;
}
template < class T>
AutoPtr<T>& AutoPtr<T>::operator=(const AutoPtr<T>& h)
{
decrUser();
m_pData = h.m_pData;
m_nUser = h.m_nUser;
(*m_nUser)++;
}
template < class T>
void AutoPtr<T>::decrUser()
{
--(*m_nUser);
if ((*m_nUser) == 0) {
delete m_pData;
m_pData = 0;
delete m_nUser;
m_nUser = 0;
}
}
template < class T>
AutoPtr<T>::~AutoPtr()
{
decrUser();
}
#endif // AUTOPTR_H