C++ Primer(第五版) 16.1.2节练习

本文介绍了C++中的函数模板和类模板,讲解了类模板在实例化过程中如何绑定模板参数,以及类模板名字与类型的区别。内容涉及Blob和BlobPtr模板的使用,以及Screen类模板的实现,还包括Vec模板的定义,并讨论了一对一友好关系和自定义输入输出运算符的添加。

16.9    函数模板是可以实例化出特定函数的模板,类模板是可以实例化出特定类的模板。

16.10    当类模板被实例化时,编译器会根据提供的模板实参列表来绑定模板参数,替换类模板定义中模板参数出现的地方,这样就实例化出一个特定的类。

16.11    类模板的名字不是类型,只有实例化后才能形成类型。在class List代码中不能直接使用ListItem,应该使用ListItem<elemType>;在类模板作用域中,可以不提供实参,因此class List代码中可以用List代替List<elemType>。

16.12    Blob和BlobPtr模板代码:

#ifndef	BLOB_H
#define	BLOB_H

#include <iostream>
#include <vector>
#include <stdexcept>
#include <memory>

using namespace std;

template <typename> class BlobPtr;

template <typename T> class Blob {
	friend class BlobPtr<T>;
public:
	typedef typename vector<T>::size_type size_type;
	Blob();
	Blob(initializer_list<T> il);
	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	void push_back(const T &t) { data->push_back(t); }
	void push_back(T &&t) { data->push_back(std::move(t)); }
	void pop_back();
	BlobPtr<T> begin() { return BlobPtr<T>(*this); }
	BlobPtr<T> end() 
	{ 
		auto ret = BlobPtr<T>(*this, data->size()); 
		return ret; 
	}
	T& front();
	T& back();
	T& operator[](size_type i);
	const T& front() const;
	const T& back() const;
	const T& operator[](size_type i) const;
private:
	shared_ptr<vector<T>> data;
	void check(size_type i, const string &msg) const;
};

template <typename T>
void Blob<T>::check(size_type i, const string &msg) const
{
	if (i >= data->size())
		throw out_of_range(msg);
}

template <typename T>
Blob<T>::Blob(): data(make_shared<vector<T>>()) { }

template <typename T>
Blob<T>::Blob(initializer_list<T> il): 
			data(make_shared<vector<T>>(il)) { }
			
template <typename T>
void Blob<T>::pop_back()
{
	check(0, "pop back on empty Blob");
	data->pop_back();
}

template <typename T>
T& Blob<T>::front()
{
	check(0, "front on empty Blob");
	return data->front();
}

template <typename T>
T& Blob<T>::back()
{
	check(0, "back on empty Blob");
	return data->back();
}

template <typename T>
T& Blob<T>::operator[](size_type i)
{
	check(i, "subscritpt out of range");
	return (*data)[i];
}

template <typename T>
const T& Blob<T>::front() const 
{
	check(0, "front on empty Blob");
	return data->front();
}

template <typename T>
const T& Blob<T>::back() const
{
	check(0, "back on empty Blob");
	return data->back();
}

template <typename T>
const T& Blob<T>::operator[](size_type i) const
{
	check(i, "subscritpt out of range");
	return (*data)[i];
}

template <typename T>
bool operator==(const BlobPtr<T>&, const BlobPtr<T>&);

template <typename T> class BlobPtr {
	friend bool 
	operator==<T>(const BlobPtr<T>&, const BlobPtr<T>&);
public:
	BlobPtr(): curr(0) { };
	BlobPtr(Blob<T> &a, size_t sz = 0):
			wptr(a.data), curr(sz) { }
	T& operator*() const
	{
		auto p = check(curr, "dereference past end");
		return (*p)[curr];
	}
	BlobPtr& operator++();
	BlobPtr& operator--();
	BlobPtr operator++(int);
	BlobPtr operator--(int);
private:
	shared_ptr<vector<T>> check(size_t, const string&) const;
	weak_ptr<vector<T>> wptr;
	size_t curr;
};

template <typename T>
shared_ptr<vector<T>> 
BlobPtr<T>::check(size_t i, const string &msg) const
{
	auto ret = wptr.lock(); 
	if (!ret)
		throw runtime_error("unbound BlobPtr");
	if (i >= ret->size()) 
		throw out_of_range(msg);
	return ret; 
}


template <typename T> 
BlobPtr<T>& BlobPtr<T>::operator++()
{
	check(curr, "increment past end of BlobPtr");
    ++curr;       
    return *this;
}

template <typename T> 
BlobPtr<T>& BlobPtr<T>::operator--()
{
	--curr;      
    check(-1, "decrement past begin of BlobPtr");
    return *this;
}

template <typename T> 
BlobPtr<T> BlobPtr<T>::operator++(int)
{
	BlobPtr ret = *this;
	++*this;
	return ret;
}

template <typename T> 
BlobPtr<T> BlobPtr<T>::operator--(int)
{
	BlobPtr ret = *this; 
	--*this;     
    return ret;  
}

template <typename T>
bool operator==(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
	return lhs.wptr.lock().get() == rhs.wptr.lock().get() && 
	       lhs.curr == rhs.curr;
}

template <typename T>
bool operator!=(const BlobPtr<T> &lhs, const BlobPtr<T> &rhs)
{
	return !(lhs == rhs);
}

#endif

16.13    选择一对一友好关系。

16.14    Screen类模板代码:

#ifndef	SCREEN_H
#define	SCREEN_H

#include <iostream>

using namespace std;

template <int H, int W> class Screen {
public:
	typedef string::size_type pos;
	Screen(): contents(H * W, ' ') { }
	Screen(char c): contents(H * W, c) { }
	char get() const { return contents[cursor]; }
	inline char get(pos, pos) const;
	Screen &move(pos r, pos c);
	Screen &set(char);
	Screen &display(ostream &os) {
		do_display(os);
		return *this;
	}
	const Screen &display(ostream &os) const {
		do_display(os);
		return *this;
	}
private:
	pos cursor = 0;
	string contents;
	void do_display(ostream &os) const { os << contents; }
};

template <int H, int W>
inline Screen<H, W> &Screen<H, W>::set(char c)
{
	contents[cursor] = c;
	return *this;
}

template <int H, int W>
inline Screen<H, W> &Screen<H, W>::move(pos r, pos c)
{
	cursor = r * W + c;
	return *this;
}

16.15    添加输入输出运算符:

#ifndef	SCREEN_H
#define	SCREEN_H

#include <iostream>

using namespace std;

template <int H, int W> class Screen;

template <int H, int W>
istream &operator>>(istream&, Screen<H, W>&);

template <int H, int W>
ostream &operator<<(ostream&, Screen<H, W>&);

template <int H, int W> class Screen {
	friend istream &operator>> <H, W>(istream&, Screen<H, W>&);
	friend ostream &operator<< <H, W>(ostream&, Screen<H, W>&);
    ...
};

template <int H, int W>
istream &operator>>(istream &is, Screen<H, W> &s)
{
	string t;
	is >> t;
	s.contents = t.substr(0, H * W);
	return is;
}

template <int H, int W>
ostream &operator<<(ostream &os, Screen<H, W> &s)
{
	os << s.contents;
	return os;
}

#endif

16.16    Vec.h文件定义Vec模板:

#ifndef	VEC_H
#define	VEC_H
#include <memory>

using namespace std;

template <typename T> class Vec {
public:
	Vec(): elements(nullptr), first_free(nullptr), cap(nullptr) { }
	Vec(const Vec&);
	Vec(const T*, const T*);
	Vec(initializer_list<T> lst);
	Vec& operator=(const Vec&);
	~Vec();
	void push_back(const T&);
	size_t size() const { return first_free - elements; }
	size_t capacity() const { return cap - elements; }
	T *begin() const { return elements; }
	T *end() const { return first_free;}
	void reserve(size_t n) { if (n > capacity()) resize(n); }
	void resize(size_t);
	T& operator[](size_t n) { return elements[n]; }
private:
	static allocator<T> alloc;
	void chk_n_alloc()
		{ if (size() == capacity() ) reallocate(); } 
	pair<T*, T*> alloc_n_copy(const T*, const T*);
	void free();
	void reallocate();
	T *elements;
	T *first_free;
	T *cap;	
};

template <typename T> std::allocator<T> Vec<T>::alloc;  

template <typename T>
void Vec<T>::push_back(const T &s)
{
	chk_n_alloc();
	alloc.construct(first_free++, s);
}

template <typename T>
pair<T*, T*> Vec<T>::alloc_n_copy(const T *b, const T *e)
{
	T *data = alloc.allocate(e - b);
	return make_pair(data, uninitialized_copy(b, e, data));
}

template <typename T>
void Vec<T>::free()
{
	if (elements) {
		for (auto p = first_free; p != elements; )
			alloc.destroy(--p);
		alloc.deallocate(elements, cap - elements);
	}
}

template <typename T>
Vec<T>::Vec(const Vec<T> &s)
{
	auto newdata = alloc_n_copy(s.begin(), s.end());
	elements = newdata.first;
	first_free = newdata.second;
	cap = newdata.second;
}

template <typename T>
Vec<T>::Vec(const T *b, const T *e)
{
	// call alloc_n_copy to allocate exactly as many elements as in il
	pair<T*, T*> newdata = alloc_n_copy(b, e);
	elements = newdata.first;
	first_free = cap = newdata.second;
}

template <typename T>
Vec<T>::Vec(initializer_list<T> lst)
{
	auto newdata = alloc_n_copy(lst.begin(), lst.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}

template <typename T>
Vec<T>::~Vec() { free(); }

template <typename T>
Vec<T> &Vec<T>::operator=(const Vec &rhs)
{
	auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
	free();
	elements = newdata.first;
	first_free = newdata.second;
	cap = newdata.second;
	return *this;
}

template <typename T>
void Vec<T>::reallocate()
{
	auto newcapacity = size()? size() * 2 : 1;
	auto newdata = alloc.allocate(newcapacity);
	auto dest = newdata;
	auto elem = elements;
	for (size_t i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*elem++));
	free();
	elements = newdata;
	first_free = dest;
	cap = elements + newcapacity;
}

template <typename T>
void Vec<T>::resize(size_t n)
{
	if (n > size()) {
		while ( n > size() )
			push_back("");
	} else if ( n < size() ){
		while (size() > n )
			alloc.destroy(--first_free);
	}
		
}

#endif

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值