栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

C++实验三:模板

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C++实验三:模板

模板
  • 一、模板函数(compare)
    • 1. 一般模板函数
    • 2. 特化模板函数
    • 3. 测试
    • 4. 小结
  • 二、模板类Queue或Stack
    • 1. 模板类(Queue,Stack)
    • 2. 成员模板函数
    • 3. 模板特化:模板函数特化、模板成员函数特化、模板类特化
      • 3.1. 模板函数特化
      • 3.2. 模板成员函数特化
      • 3.3. 模板类特化
    • 4. 代码:
      • queue.h
      • queue.cpp
      • Test.cpp
  • 三、模板类AutoPtr
    • 1. 构造函数
    • 2. 析构函数
    • 3. 拷贝构造函数
    • 4. 等号、->、*等运算符重载
    • 5. 主函数调用AutoPtr
    • 6. 总结

一、模板函数(compare) 1. 一般模板函数

首先写一个判断是否相等的模板函数,注意声明和函数体都写在头文件中。

//模板函数需要将声明和函数体都放在头文件中
//一般模板函数
template
bool compare(const T& a, const T& b)
{
	return a == b;
}
2. 特化模板函数

使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数。
此处,该函数无法针对字符串类型使用,则需特化模板函数。

//上述模板函数对于字符串比较无法使用,所以需要特化
//格式:template<>不用写类型
//      函数名<特化类型>(特化类型 参数1, 特化类型 参数2,...)
//注意声明必须放在头文件中,实例化必须在cpp文件中
template<>
bool compare(const char* const& a, const char* const& b);
template<>
bool compare(const char* const& a, const char* const& b)
{
	return strcmp(a, b) == 0;
}
3. 测试
#include
#include"queue.h"
using namespace std;
int main()
{
	const int a = 1;
	const int b = 1;
	const char* c = "qwe", * d = "asd";
	cout << compare(a, b) << endl;
	cout << compare(c, d);
}

运行结果:

4. 小结

一般特化函数格式

template< 模板参数表>
类型名 参数名(参数表)
{
	函数体的定义
}

特化模板函数注意点

  1. 使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)
  2. 使用特换模板函数时格式有要求:
    2.1. template 后直接跟<> 里面不用写类型
    2.2. 函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型
  3. 特化的函数的函数名,参数列表要和原基础的模板函数想相同,避免不必要的错误
  4. 声明必须放在头文件中,实例化必须在cpp文件中

函数模板与函数的区别

  1. 函数模板本身在编译时不会生成任何目标代码,只有由模板生成的实例会生成目标代码。
  2. 被多个源文件引用的函数模板,应当连同函数体一同放在头文件中,而不能像普通函数那样只将声明放在头文件中。
  3. 函数指针也只能指向模板的实例,而不能指向模板本身。
二、模板类Queue或Stack 1. 模板类(Queue,Stack)

类模板格式:

template<模板参数表>
class 类名
{
	类成员声明
};

如类模板QueueItem

template class QueueItem
{
	QueueItem(const Type &t) :item(t), next(0){}
	Type item;
	QueueItem * next;
	friend class Queue;
	friend ostream& operator<<(ostream& os,const Queue &q);
public:
	QueueItem* operator++()
	{
		return next;
	}
	Type & operator*()
	{
		return item;
	}
};

模板参数表中参数可以声明为该模板类的友元类
如以上代码第6,7行的友元类
可通过typedef或者using对实例化的类模板定义别名

2. 成员模板函数
  • 在类模板中直接声明然后实例化
  • 如果需要在类模板以外定义其成员函数,则要采用以下的形式(现在类模板中声明成员函数):
template<模板参数表>
类型名 类名<模板参数标识符列表>::函数名(参数表){}
template c1ass Queue
{
public:
	Queue():head(0),tail(0){}
	Queue(const Queue& q):head(0),tail(0)
	{
		copy_items(q);
	}
	template
	Queue(It beg, It end):head(0),tail(0)
	{
		copy_items(beg,end);
	}
	template void assign(It beg, It end);
};
template template 
void Queue::assign(It beg,It end)
{
	destroy();
	copy_items(beg,end);
}
3. 模板特化:模板函数特化、模板成员函数特化、模板类特化 3.1. 模板函数特化

模板函数特化见目录一、模板函数 2.特化模板函数

3.2. 模板成员函数特化

头文件中声明

template<>
void Queue::push(const char * const &val) ;
template<>
void Queue::pop();

cpp文件中实现

template<>
void Queue::push(const char * const &val)
{
	char* new_item = new char[str1en(va1)+1];
	strncpy(new_item, val, strlen(va1)+1);
	QueueItem * pt = new QueueItem(new_item);
	if(empty())
	{
		head=tail=pt;
	}
	else
	{
		tail->next = pt;
		tail = pt;
	}
}
template<>
void Queue::pop()
{
	QueueItem * p = head;
	delete head->item;
	head = head- >next;
	delete p;
}
3.3. 模板类特化
//普通类模板
template<模板参数表>
class 类名
{
	类成员声明
};

//模板类特化
template<> 			//<>里为空
class 类名<特化类型> //<>里指明具体类型
{
	类成员声明
};
4. 代码: queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include 
using namespace std;
//模板函数需要将声明和函数体都放在头文件中
//一般模板函数
template
bool compare(const T& a, const T& b)
{
	return a == b;
}
//上述模板函数对于字符串比较无法使用,所以需要特化
//格式:template<>不用写类型
//      函数名<特化类型>(特化类型 参数1, 特化类型 参数2,...)
//注意声明必须放在头文件中,实例化必须在cpp文件中
template<>
bool compare(const char* const& a, const char* const& b);

template class Queue;
template class QueueItem
{
	QueueItem(const Type &t) :item(t), next(0){}
	Type item;
	QueueItem * next;
	friend class Queue;
	friend ostream& operator<<(ostream& os,const Queue &q);
public:
	QueueItem* operator++()
	{
		return next;
	}
	Type & operator*()
	{
		return item;
	}
};

template 
class Queue
{
public:
	Queue():head(0),tail(0){}
	Queue(const Queue& q):head(0),tail(0)
	{
		copy_items(q);
	}
	template
	Queue(It beg, It end):head(0),tail(0)
	{
		copy_items(beg,end);
	}
	template 
	void assign(It beg, It end);
	Queue& operator=(const Queue&);
	~Queue()
	{
		destroy();
	}
	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 &q)
	{
		os<<"< ";
		QueueItem* p;
		for(p=q.head;p;p=p->next)
		{
			os<item<<" ";
		}
		os<<">";return os;
	}
	const QueueItem* Head() const
	{
		return head;
	}
	const QueueItem*End() const
	{
		return (tail==NULL)?NULL:tail->next;
	}
private:
	QueueItem* head;
	QueueItem* tail;
	void destroy();
	void copy_items(const Queue &);
	template 
	void copy_items(It beg,It end);
};

templatevoid Queue::destroy()
{
	while (!empty())
	{
		pop();
	}
}

template void Queue::pop()
{
	QueueItem * p = head;
	head = head->next;
	delete p;
}
	
template void Queue::push(const Type& val)
{
	QueueItem * pt = new QueueItem(val);
	if(empty())
	{
		head = tail = pt;
	}
	else
	{
		tail->next = pt;
		tail = pt;
	}
}
template<>
void Queue::push(const char * const &val) ;
template<>
void Queue::pop();

template
void Queue::copy_items(const Queue &orig)
{
	for(QueueItem *pt = orig.head;pt;pt=pt->next)
	{
		push(pt->item);
	}
}

template
Queue& Queue::operator=(const Queue& q)
{
	destroy();
	copy_items(q);
}

template template 
void Queue::assign(It beg,It end)
{
	destroy();
	copy_items(beg,end);
}

template template 
void Queue::copy_items(It beg,It end)
{
	while(beg!=end)
	{
		push(*beg);
		++beg;
	}
}

#endif // QUEUE_H
queue.cpp
#include "queue.h"
#include 
template<>
bool compare(const char * const &a, const char * const &b)
{
	return strcmp(a,b) == 0;
}

template<>
void Queue::push(const char * const &val)
{
	char* new_item = new char[strlen(val)+1];
	strncpy(new_item, val, strlen(val)+1);
	QueueItem * pt = new QueueItem(new_item);
	if(empty())
	{
		head=tail=pt;
	}
	else
	{
		tail->next = pt;
		tail = pt;
	}
}
template<>
void Queue::pop()
{
	QueueItem * p = head;
	delete head->item;
	head = head- >next;
	delete p;
}
Test.cpp
#include
#include"queue.h"
#include 
#include "autoptr.h"
#include "CMatrix.h"
using namespace std;
int main()
{
	//const int a = 1;
	//const int b = 1;
	//const char* c = "qwe", * d = "asd";
	//cout << compare(a, b) << endl;
	//cout << compare(c, d);


	Queue qt;
	double d = 3.3;
	qt.push(1);
	qt.push(d);
	qt.push(10); 
	cout << endl;
	cout << qt;

	short a[5] = { 0,3,6,9 };
	Queue qi(a, a + 5);
	cout << endl;
	cout << qi;
	cout << endl;
	while (!qi.empty())
	{
		cout << qi.front() << " ";
		qi.pop();
	}
	vector vi(a, a + 5);
	qi.assign(vi.begin(), vi.end());
	cout << endl;
	cout << qi;
	cout << endl;

	Queue q1;
	q1.push("hi");
	q1.push("I'm");
	q1.push("Jerry");
	cout << q1;
	cout << endl;
	Queue q2(q1);
	cout << q2;


    //AutoPtr h1;
    //double data[6] = {1,2,3,4,5,6};
    //h1->Create(2,3,data);
    //AutoPtr h2(h1);
    //(*h2).Set(0,1,10);
    //cout<<*h1<<*h2;
}

运行结果:

三、模板类AutoPtr 1. 构造函数

函数声明

AutoPtr(T* pData);

函数实例化

template
AutoPtr::AutoPtr(T* pData)
{
	m_pData = pData;
	m_nUser = new int(1);
}
2. 析构函数
~AutoPtr()
	{
		decrUser();
	}
void decrUser();
template
void AutoPtr::decrUser()
{
	--(*m_nUser);
	if ((*m_nUser) == 0)
	{
		delete m_pData;
		m_pData = 0;
		delete m_nUser;
		m_nUser = 0;
	}
}
3. 拷贝构造函数

函数声明

AutoPtr(const AutoPtr& h);

函数实例化

template
AutoPtr::AutoPtr(const AutoPtr& h)
{
	m_pData = h.m_pData;
	m_nUser = h.m_nUser;
	(*m_nUser)++;
}
4. 等号、->、*等运算符重载
AutoPtr& operator=(const AutoPtr& h);
T* operator->()
{
	return m_pData;
}
T& operator*()
{
	return *m_pData;
}
const T& operator *()const
{
	return *m_pData;
}
const T* operator ->()const
{
	return m_pData;
}
template
AutoPtr& AutoPtr::operator=(const AutoPtr& h)
{
	decrUser();
	m_pData = h.m_pData;
	m_nUser = h.m_nUser;
	(*m_nUser)++;
}
5. 主函数调用AutoPtr
#include
#include"queue.h"
#include 
#include "autoptr.h"
#include "CMatrix.h"
using namespace std;
int main()
{
	//const int a = 1;
	//const int b = 1;
	//const char* c = "qwe", * d = "asd";
	//cout << compare(a, b) << endl;
	//cout << compare(c, d);


	//Queue qt;
	//double d = 3.3;
	//qt.push(1);
	//qt.push(d);
	//qt.push(10); 
	//cout << endl;
	//cout << qt;

	//short a[5] = { 0,3,6,9 };
	//Queue qi(a, a + 5);
	//cout << endl;
	//cout << qi;
	//cout << endl;
	//while (!qi.empty())
	//{
	//	cout << qi.front() << " ";
	//	qi.pop();
	//}
	//vector vi(a, a + 5);
	//qi.assign(vi.begin(), vi.end());
	//cout << endl;
	//cout << qi;
	//cout << endl;

	//Queue q1;
	//q1.push("hi");
	//q1.push("I'm");
	//q1.push("Jerry");
	//cout << q1;
	//cout << endl;
	//Queue q2(q1);
	//cout << q2;


    AutoPtr h1;
    double data[6] = {1,2,3,4,5,6};
    h1->Create(2,3,data);
    cout << *h1 << endl;
    AutoPtr h2(h1);
    (*h2).Set(0,1,10);
    cout << *h1 << endl << *h2;
}

运行结果如下:h2通过拷贝构造函数创建(拷贝h1),则h2调用Set方法后改变的是同一个地址的值,所以最后h1改变了,h1和h2输出结果相同。

6. 总结

在C++中,动态内存的管理是用一对运算符完成的:new和delete,new:在动态内存中为对象分配一块空间并返回一个指向该对象的指针,delete:指向一个动态独享的指针,销毁对象,并释放与之关联的内存。

动态内存管理经常会出现两种问题:一种是忘记释放内存,会造成内存泄漏;一种是尚有指针引用内存的情况下就释放了它,就会产生引用非法内存的指针。

为了更加容易(更加安全)的使用动态内存,引入了智能指针的概念。智能指针的行为类似常规指针,重要的区别是它负责自动释放所指向的对象。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/529070.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号