【C++】模板函数与模板类的设计与使用

150 阅读4分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

【C++】模板函数与模板类的设计与使用

一、实验目的与要求

模板函数与模板类的设计与使用

二、实验结果

1.模板类Queue实现结果

image.png

2.模板类Handle实现结果

image.png

三、实验分析与总结

在实验过程中,刚开始由于对template模板类不够熟悉,因此在项目编写过程中出现了很多问题。例如模板函数调用错误、模板类定义错误、成员重复定义等等。后续在通过复习老师上课所讲的知识加上与同学交流、通过互联网工具查询的方式逐渐对模板类与模板函数在项目中的实现有了更加深入的理解。并在多次查阅资料与理解后熟悉了实验中的内容,同时也更好的能够通过模板与智能指针完成实验对Queue与Handle的实现。 实验中我们通过模板类的机制,只需要写一个可变长的数组类模板,编译器就会由该类模板自动生成各种类型的可变长数组类。我们的模版为生成通用的类声明提供了一种更好的方法,例如在Queue类实现实验中,我们将类型char传递给Queue模版,可以让模版构造一个对char进行排队的Queue类模版提供参数化类型,即能通过类型名作为参数传递给接收方来简历Queue类。

同时在实验过程中我们使用模板遇到了一些特殊的类型需要特殊处理,例如实验中的It类。我们不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板类,写出一个模板类template专门给该类型使用。对于其他一些不能直接进行的操作我们因此直接特化出一个专门供字符串使用的模板参数,例如将字符导入队列。此时不添加类型模板,直接使用空即可,如template<>void Queue<const char*>。 在运算符重载中,对于输出符 ”<<” 由于经常要访问私有变量,所以普遍写成友元函数的形式,而对于 ”+” ”-” “+=”等运算符的调用我们可直接通过公共的成员函数实现。而在模板类的运算符重载中,”=”号等运算符被重载后相当于该类的一个成员函数,例如实验中对”+”运算符的重载模板类定义:templateHandle& Handle::operator=(const Handle& h),以此来根据模板实现对我们自己定义类型数据的”+”运算。另外,若使用友元,类里的友元声明需要使用其他模板参数名,

对于智能指针的使用,在Handle类中每次创建类的新对象时,初始化指针并将引用计数use置为1,当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数。对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数,如果引用计数为减至0,则删除对象如:if (-- * use == 0) {delete ptr;delete use;}。在调用析构函数~Handle()时,析构函数减少引用计数同样的如果引用计数减至0,则删除对应对象。

四、关键源代码

handle.h

#ifndef HANDLE_H
#define HANDLE_H
#include <bits/stdc++.h>

using namespace std;
template<class T>
class Handle {
public:
	Handle (T *p=0):ptr(p),use(new size_t(1)){}
	Handle(const Handle& h) :ptr(h.ptr), use(h.use) {
		++* use;
	}
	Handle& operator =(const Handle& h);
	~Handle() {
		rem_ref();
	}
	T& operator*();
	T* operator->();
	const T& operator *() const;
	const T* operator ->() const;
private:
	T* ptr;
	size_t* use;
	void rem_ref() {
		if (-- * use == 0) {
			delete ptr;
			delete use;
		}
	}

};

template<class T>
inline T& Handle<T>::operator*()
{
	if (ptr)
		return *ptr;
	throw runtime_error("access through unbound handle");
}

template<class T>
inline const T& Handle<T>::operator*() const
{
	if (ptr)
		return *ptr;
	throw runtime_error("access through unbound handle");
}

template<class T>
inline T* Handle<T>::operator->()
{
	return ptr;
}

template<class T>
inline const T* Handle<T>::operator->() const
{
	return ptr;
}

template<class T>
Handle<T>& Handle<T>::operator=(const Handle& h)
{
	rem_ref();
	++* h.use;
	ptr = h.ptr;
	use = h.use;
	return *this;
}
class Item_base {
private:
	string isbn;
protected:
	double price;
public :
	Item_base(const string &book="",double sales_price=0.0):
		isbn(book),price(sales_price){}
	Item_base(const Item_base& item) {
		isbn = item.isbn;
		price = item.price;
	}
	string book()const {
		return isbn;
	}
	Item_base& operator=(const Item_base& item) {
		isbn = item.isbn;
		price = item.price;
		return *this;
	}
	virtual Item_base* clone() const {
		return new Item_base(isbn, price);
	}
	virtual double net_price(size_t n) const {
		return n * price;
	}
	virtual ~Item_base() {}
};

class Bulk_item :public Item_base {
private:
	size_t min_qty;
	double discount;
public:
	Bulk_item(const string &book,double sales_price,size_t qty=10,double disc_rate=0.8):
		Item_base(book,sales_price),min_qty(qty),discount(disc_rate){}
	Bulk_item(const Bulk_item& item) {
		*this = item;
	}
	double net_price(size_t n) const {
		if (n < min_qty) {
			return n * price;
		}
		else {
			return n * price*(1 - discount);
		}
	}
	Bulk_item& operator =(const Bulk_item& item) {
		Item_base::operator=(item);
		min_qty = item.min_qty;
		discount = item.discount;
		return *this;
	}
	Bulk_item* clone() const {
		return new Bulk_item(*this);
	}
};

class Sales_item {
private:
	Handle<Item_base> h;
public:
	Sales_item():h(){}
	Sales_item(const Item_base& item):h(item.clone()){}
	const Item_base& operator*() const {
		return *h;
	}
	const Item_base* operator->() const {
		return h.operator->();
	}
};
inline bool compare(const Sales_item& lhs, const Sales_item& rhs) {
	return lhs->book() < rhs->book();
}

class Basket {
	typedef bool(*Comp)(const Sales_item&, const Sales_item&);
private:
	multiset < Sales_item, Comp> items;
public:
	typedef multiset< Sales_item, Comp> set_type;
	typedef set_type::size_type size_type;
	typedef set_type::const_iterator const_iter;
	Basket():items(compare){}
	void add_item(const Sales_item& item) {
		items.insert(item);
	}
	size_type size(const Sales_item& i)const {
		return items.count(i);
	}
	double total()const {
		double sum = 0.0;
		for (const_iter iter = items.begin(); iter != items.end(); iter = items.upper_bound(*iter)) {
			sum += (*iter)->net_price(items.count(*iter));
		}
		return sum;
	}
};

#endif // HANDLE_H
    

main.cpp


#include <bits/stdc++.h>
#include "handle.h"
int main(int argc, char *argv[])
{
Basket basket;
Item_base b("Ling",10);
Bulk_item d("CT",10,2,0.2);
basket.add_item(Sales_item(b));
basket.add_item(Sales_item(d));
basket.add_item(Sales_item(d));
basket.add_item(Sales_item(d));
basket.add_item(Sales_item(d));
basket.add_item(Sales_item(b));
cout<<basket.total()<<endl;
}