1. 程式人生 > >C++Primer Plus筆記——第十四章 C++中的程式碼重用總結及程式清單

C++Primer Plus筆記——第十四章 C++中的程式碼重用總結及程式清單

目錄

本章小結

程式清單

本章小結

        C++提供了幾種重用程式碼的手段。第13章介紹的公有繼承能夠建立is-a關係,這樣派生類可以重用基類的程式碼。私有繼承和保護繼承也使得能夠重用基類的程式碼。但建立的是has-a關係。使用私有繼承時,基類的公有成員和保護成員成為派生類的私有成員;使用保護繼承時,基類的公有成員和保護成員將成為派生類的保護成員。無論是用哪種繼承,基類的公有介面都將成為派生類的內部介面。這有時候被稱為繼承實現,但並不繼承介面,因為派生類物件不能顯式地使用基類的介面。因此,不能將派生物件看做是一種基類物件。由於這個原因,在不進行顯式型別轉化的情況下,基類指標或引用將不能指向派生類物件。

        還可以通過開發包含物件成員的類來重用類程式碼。這種方法被稱為包含、層次化或組合,它建立的也是has-a關係。與私有繼承和保護繼承相比,包含更容易實現和使用,所以通常優先採用這種方式。然而,私有繼承和保護繼承相比包含有一些不同的功能。例如,繼承允許派生類訪問基類的保護成員;還允許派生類重新定義從基類那繼承的虛擬函式。因為包含不是繼承,所以通過包含來重用程式碼時,不能使用這些功能。另一方面,如果需要使用某個類的幾個物件,則用包含更合適。例如,State類可以包含一組County物件。

        多重繼承(MI)使得能夠在類設計中重用多個類的程式碼。私有MI或保護MI建立has-a關係,而公有MI建立is-a關係。MI會帶來一些問題,即多次定義同一個名稱,繼承多個基類物件。可以使用類限定符來解決名稱二義性的問題,使用虛基類來避免繼承多個基類物件的問題。但使用虛基類後,就需要為編寫建構函式初始化列表以及解決二義性問題引入新的規則。

        類模板使得能夠建立通用的類設計,其中型別(通常是成員型別)由型別引數表示。典型的模板如下:

template <class T>
class Ic
{
    T v;
    ...
public:
    Ic(const T &val) : v(val) {}
};

        其中,T是型別引數,用作以後指定的實際型別的佔位符。在這種環境下,也可以使用typename代替class:

template <typename T>
class Rev {...};

        類定義在宣告類物件並指定特定型別時生成。例如,下面的宣告導致編譯器生成類宣告,用宣告中的實際型別short替換模板中的所有型別引數T:

class Ic<short> sic;

        這裡,類名為Ic<short>,而不是Ic。具體地說這是一個隱式例項化。

        使用關鍵字template宣告類的特定具體化時,將發生顯式例項化:

template class Ic<int>;

        在這種情況下,編譯器將使用通用模板生成一個int具體化——Ic<int>。

        可以提供顯示具體化——覆蓋模板定義的具體類宣告:

template <> class Ic<char *>
{
    char *str;
    ...
public:
    Ic(const char * s) : str(s) {}
}

        所有這些機制的目的都是為了讓程式設計師能夠重用經過測試的程式碼,而不用手工複製它們。這樣可以簡化程式設計工作,提高程式可靠性。

程式清單

使用valarray物件建立Student類

14.1 studentc.h

//studentc.h -- defining a Student class using containment
#ifndef STUDENTC_H_
#define STUDENTC_H_

#include <iostream>
#include <string>
#include <valarray>

using namespace std;

class Student
{
private:
	typedef valarray<double> ArrayDb;
	string name;
	ArrayDb scores;
	ostream & arr_out(ostream & os) const;
public:
	Student(): name("Null Student"),scores() {}
	explicit Student(const string & s):name(s),scores() {}
	explicit Student(int n):name("Nully"),scores(n) {}
	Student(const string & s,int n):name(s),scores(n) {}
	Student(const string & s, const ArrayDb & a) :name(s), scores(a) {}
	Student(const char * str, const double * pd, int n) :name(str), scores(pd, n) {}
	~Student() {}
	double Average() const;
	const string & Name() const;
	double & operator[](int i);
	double operator[](int i) const;

	friend istream & operator>>(istream & is, Student & stu);
	friend istream & getline(istream & is, Student & stu);
	friend ostream & operator<<(ostream & os, const Student & stu);
};
#endif // !STUDENTC_H_

14.2 studentc.cpp

//studentc.cpp -- Student class using containment
#include "studentc.h"

using namespace std;

double Student::Average() const
{
	if (scores.size() > 0)
		return scores.sum() / scores.size();
	else
		return 0;
}

const string & Student::Name() const
{
	return name;
}

double & Student::operator[](int i)
{
	return scores[i];
}

double Student::operator[](int i) const
{
	return scores[i];
}

ostream & Student::arr_out(ostream & os) const 
{
	int i;
	int lim = scores.size();
	if (lim > 0)
	{
		for (i = 0; i < lim; i++)
		{
			os << scores[i] << " ";
			if (i % 5 == 4)
				os << endl;
		}
		if (i % 5 != 0)
			os << endl;
	}
	else
		os << " empty array ";
	return os;
}

istream & operator>>(istream & is, Student & stu)
{
	is >> stu.name;
	return is;
}

istream & getline(istream & is, Student & stu)
{
	getline(is, stu.name);
	return is;
}

ostream & operator<<(ostream & os, const Student & stu)
{
	os << "Scores for " << stu.name << ":\n";
	stu.arr_out(os);
	return os;
}

14.3 use_stuc.cpp

//use_stuc.cpp -- using a composite class
//compile with studentc.cpp

#include <iostream>
#include "studentc.h"

using namespace std;

void set(Student & sa, int n);
const int pupils = 3;
const int quizzes = 5;

int studentc()
{
	Student ada[pupils] = { Student(quizzes), Student(quizzes),Student(quizzes) };
	int i;
	for (i = 0; i < pupils; ++i)
		set(ada[i], quizzes);
	cout << "\nStudent List:\n";
	for (i = 0; i < pupils; ++i)
		cout << ada[i].Name() << endl;
	cout << "\nResults:";
	for (i = 0; i < pupils; ++i)
		cout << endl << ada[i] << "average: " << ada[i].Average() << endl;
	cout << "Done.\n";
	return 0;
}

void set(Student & sa, int n)
{
	cout << "Please enter the student's name: ";
	getline(cin, sa);
	cout << "Please enter " << n << " quiz scores:\n";
	for (int i = 0; i < n; i++)
		cin >> sa[i];
	while (cin.get() != '\n')
		continue;
}

使用string類和valarray類派生Student類

14.4 studenti.h

//studenti.h -- defining a Student class using private inheritance
#ifndef STUDENTC_H_
#define STUDENTC_H_
#include <iostream>
#include <valarray>
#include <string>

using namespace std;

class Student : private string, private valarray<double>
{
private:
	typedef valarray<double> ArrayDb;
	ostream & arr_out(ostream & os) const;
public:
	Student() : string("Null Student"), ArrayDb() {}
	explicit Student(const string &s):string(s),ArrayDb() {}
	explicit Student(int n) :string("Nully"), ArrayDb(n) {}
	Student(const string & s, int n):string(s),ArrayDb(n) {}
	Student(const string & s, const ArrayDb & a) :string(s), ArrayDb(a) {}
	Student(const char * str, const double * pd, int n) :string(str), ArrayDb(pd, n) {}
	~Student() {}
	double Average() const;
	double & operator[](int i);
	double operator[](int i) const;
	const string & Name() const;

	friend istream & operator>>(istream & is, Student & stu);
	friend istream & getline(istream & is, Student & stu);
	friend ostream & operator<<(ostream & os, const Student & stu);
};

#endif // !STUDENTC_H_

14.5 studenti.cpp

//studenti.cpp -- Student class using private in heritance
#include "studenti.h"

using namespace std;

double Student::Average() const
{
	if (ArrayDb::size() > 0)
		return ArrayDb::sum() / ArrayDb::size();
	else
		return 0;
}

const string & Student::Name() const
{
	return (const string &) *this;
}

double & Student::operator[](int i)
{
	return ArrayDb::operator[] (i);
}

double Student::operator[](int i) const
{
	return ArrayDb::operator[] (i);
}

ostream & Student::arr_out(ostream & os) const
{
	int i;
	int lim = ArrayDb::size();
	if (lim > 0)
	{
		for (i = 0; i < lim; i++)
		{
			os << ArrayDb::operator[] (i) << " ";
			if (i % 5 == 4)
				os << endl;
		}
		if (i % 5 != 0)
			os << endl;
	}
	else
		os << " empty array ";
	return os;
}

istream & operator>>(istream & is, Student & stu)
{
	is >> (string &) stu;
	return is;
}

istream & getline(istream & is, Student & stu)
{
	getline(is, (string &) stu);
	return is;
}

ostream & operator<<(ostream & os, const Student & stu)
{
	os << "Scores for " << (const string &) stu << ":\n";
	stu.arr_out(os);
	return os;
}

14.6 use_stui.cpp

//use_stui.cpp -- using a class with private inheritance
//compile with studenti.cpp
#include <iostream>
#include "studenti.h"

using namespace std;

void set(Student & sa, int n);
const int pupils = 3;
const int quizzes = 5;

int studentc()
{
	Student ada[pupils] = { Student(quizzes), Student(quizzes),Student(quizzes) };
	int i;
	for (i = 0; i < pupils; ++i)
		set(ada[i], quizzes);
	cout << "\nStudent List:\n";
	for (i = 0; i < pupils; ++i)
		cout << ada[i].Name() << endl;
	cout << "\nResults:";
	for (i = 0; i < pupils; ++i)
		cout << endl << ada[i] << "average: " << ada[i].Average() << endl;
	cout << "Done.\n";
	return 0;
}

void set(Student & sa, int n)
{
	cout << "Please enter the student's name: ";
	getline(cin, sa);
	cout << "Please enter " << n << " quiz scores:\n";
	for (int i = 0; i < n; i++)
		cin >> sa[i];
	while (cin.get() != '\n')
		continue;
}

多重繼承

14.7 worker0.h

//worker0.h -- working classes
#ifndef WORKER0_H_
#define WORKER0_H_
#include <string>

using namespace std;

class Worker
{
private:
	string fullname;
	long id;
public:
	Worker() : fullname("no one"), id(0L) {}
	Worker(const string & s, long n) : fullname(s), id(n) {}
	virtual ~Worker() = 0;
	virtual void Set();
	virtual void Show() const;
};

class Waiter : public Worker
{
private:
	int panache;
public:
	Waiter() : Worker(), panache(0) {}
	Waiter(const string & s, long n, int p = 0) : Worker(s, n), panache(p) {}
	Waiter(const Worker & wk, int p = 0) : Worker(wk), panache(p) {}
	void Set();
	void Show() const;
};

class Singer : public Worker
{
protected:
	enum { other, alto, contralto, soprano, bass, baritone, tenor };
	enum { Vtypes = 7 };
private:
	static char *pv[Vtypes];
	int voice;
public:
	Singer() : Worker(), voice(other) {}
	Singer(const string & s, long n, int v = other) : Worker(s, n), voice(v) {}
	Singer(const Worker & wk, int v = other) : Worker(wk), voice(v) {}
	void Set();
	void Show() const;
};
#endif // !WORKER0_H_

14.8 worker0.cpp

//worker0.cpp -- working class methods
#include "worker0.h"
#include <iostream>

using namespace std;

Worker::~Worker() {}

void Worker::Set()
{
	cout << "Enter worker's name: ";
	getline(cin, fullname);
	cout << "Enter worker's ID: ";
	cin >> id;
	while (cin.get() != '\n')
		continue;
}

void Worker::Show() const
{
	cout << "Name: " << fullname << "\n";
	cout << "Employee ID: " << id << "\n";
}

void Waiter::Set()
{
	Worker::Set();
	cout << "Enter waiter's panache rating: ";
	cin >> panache;
	while (cin.get() != '\n')
		continue;
}

void Waiter::Show() const
{
	cout << "Category: waiter\n";
	Worker::Show();
	cout << "Panache rating: " << panache << "\n";
}

char * Singer::pv[] = { "other", "alto", "contralto", "soprano", "bass", "baritone", "tenor" };

void Singer::Set()
{
	Worker::Set();
	cout << "Enter number for singer's vocal range:\n";
	int i;
	for (i = 0; i < Vtypes; i++)
	{
		cout << i << ": " << pv[i] << " ";
		if (i % 4 == 3)
			cout << endl;
	}
	if (i % 4 != 0)
		cout << endl;
	while (cin >> voice && (voice < 0 || voice >= Vtypes))
		cout << "Please enter a value >= 0 and < " << Vtypes << endl;

	while (cin.get() != '\n')
		continue;
}

void Singer::Show() const
{
		cout << "Category: singer\n";
		Worker::Show();
		cout << "Vocal range: " << pv[voice] << endl;
}

14.9worktest.cpp

//worktest.cpp -- test worker class hierarchy
#include <iostream>
#include "worker0.h"

const int LIM = 4;

int main()
{
	Waiter bob("Bob Apple", 314L, 5);
	Singer bev("Beverly Hills", 522L, 3);
	Waiter w_temp;
	Singer s_temp;

	Worker * pw[LIM] = { &bob, &bev, &w_temp, &s_temp };
	
	int i;
	for (i = 2; i < LIM; i++)
		pw[i]->Set();
	for (i = 0; i < LIM; i++)
	{
		pw[i]->Show();
		cout << std::endl;
	}

	return 0;
}

虛基類

14.10 workermi.h

//workermi.h -- working classes with MI
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>

using namespace std;

class Worker
{
private:
	string fullname;
	long id;
protected:
	virtual void Data() const;
	virtual void Get();
public:
	Worker() : fullname("no one"), id(0L) {}
	Worker(const string & s, long n) : fullname(s), id(n) {}
	virtual ~Worker() = 0;
	virtual void Set() = 0;
	virtual void Show() = 0;
};

class Waiter : virtual public Worker
{
private:
	int panache;
protected:
	void Data() const;
	void Get();
public:
	Waiter() : Worker(), panache(0) {}
	Waiter(const string & s, long n, int p = 0) : Worker(s, n), panache(p) {}
	Waiter(const Worker & wk, int p = 0) : Worker(wk), panache(p) {}
	void Set();
	void Show() const;
};

class Singer : virtual public Worker
{
protected:
	enum { other, alto, contralto, soprano, bass, baritone, tenor };
	enum { Vtypes = 7 };
protected:
	void Data() const;
	void Get();
private:
	static char *pv[Vtypes];
	int voice;
public:
	Singer() : Worker(), voice(other) {}
	Singer(const string & s, long n, int v = other) : Worker(s, n), voice(v) {}
	Singer(const Worker & wk, int v = other) : Worker(wk), voice(v) {}
	void Set();
	void Show() const;
};

class SingingWaiter : public Singer, public Waiter
{
protected:
	void Data() const;
	void Get();
public:
	SingingWaiter() {}
	SingingWaiter(const string & s, long n, int p = 0, int v = other) : Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
	SingingWaiter(const Worker & wk, int p = 0, int v = other) : Worker(wk), Waiter(wk, p), Singer(wk, v) {}
	SingingWaiter(const Waiter & wt, int v = other) : Worker(wt), Waiter(wt), Singer(wt, v) {}
	SingingWaiter(const Singer & wt, int p = 0) : Worker(wt), Waiter(wt, p), Singer(wt, v) {}
	void Set();
	void Show() const;
};

#endif // !WORKERMI_H_

14.11 workermi.cpp

//workermi.cpp -- working class methods with MI
#include "workermi.h"
#include <iostream>

using namespace std;

Worker::~Worker() {}

void Worker::Data() const
{
	cout << "Name: " << fullname << endl;
	cout << "Employee ID: " << id << endl;
}

void Worker::Get()
{
	getline(cin, fullname);
	cout << "Enter worker's ID: ";
	cin >> id;
	while (cin.get() != '\n')
		continue;
}

void Waiter::Set()
{
	cout << "Enter waiter's name: ";
	Worker::Get();
	Get();
}


void Waiter::Show() const
{
	cout << "Category: waiter\n";
	Worker::Data();
	Data();
}

void Waiter::Data() const
{
	cout << "Panache rating: " << panache << endl;
}

void Waiter::Get()
{
	cout << "Enter waiter's panache rating: ";
	cin >> panache;
	while (cin.get() != '\n')
		continue;
}

char * Singer::pv[Singer::Vtypes] = { "other", "alto", "contralto", "soprano", "bass", "baritone", "tenor" };

void Singer::Set()
{
	cout << "Enter singer's name: ";
	Worker::Get();
	Get();
}

void Singer::Show() const
{
	cout << "Category: singer\n";
	Worker::Data();
	Data();
}

void Singer::Data() const
{
	cout << "Vocal range: " << pv[voice] << endl;
}

void Singer::Get()
{
	cout << "Enter number for singer's vocal range:\n";
	 int i;
	for (i = 0; i < Vtypes; i++)
	 {
	 	cout << i << ": " << pv[i] << " ";
	 	if (i % 4 == 3)
	 		cout << endl;
	 }
	 if (i % 4 != 0)
	 	cout << endl;
	 cin >> voice;
	 while (cin.get() != '\n')
	 	continue;
}

void SingingWaiter::Data() const
{
	Waiter::Data();
	Singer::Data();
}

void SingingWaiter::Get()
{
	Waiter::Get();
	Singer::Get();
}

void SingingWaiter::Set()
{
	cout << "Enter singing waiter's name: ";
	Worker::Get();
	Get();
}

void SingingWaiter::Show() const
{
	cout << "Category: singing waiter\n";
	Worker::Data();
	Data();
}

14.12 workmi.cpp

//workmi.cpp -- multiple inheritance
//compile with workermi.cpp
#include <iostream>
#include <cstring>
#include "workermi.h"

const int SIZE = 5;

int main()
{
	using namespace std;

	Worker * lolas[SIZE];
	int ct;
	for (ct = 0; ct < SIZE; ct++)
	{
		char choice;
		cout << "Enter the employee category:\n"
			<< "w: waiter  s: singer  "
			<< "t: singing waiter  q: quit\n";
		cin >> choice;
		while (strchr("wstq", choice) == NULL)
		{
			cout << "Please enter a, w, s, t, or q: ";
			cin >> choice;
		}
		if (choice == 'q')
			break;
		switch (choice)
		{
		case 'w': lolas[ct] = new &Waiter;
			break;
		case 's': lolas[ct] = new &Singer;
			break;
		case 't': lolas[ct] = new &SingingWaiter;
			break;
		}
		cin.get();
		lolas[ct]->Set();
	}

	cout << "\nHere is your staff:\n";
	int i;
	for (i = 0; i < ct; i++)
	{
		cout << endl;
		lolas[i]->Show();
	}
	for (i = 0; i < ct; i++)
		delete lolas[i];
	cout << "Bye.\n";
	return 0;
}

定義一個棧類模板

14.13 stacktp.h

//stacktp.h -- a stack template
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>

class Stack
{
private:
	enum { MAX = 10 };
	Type items[MAX];
	int top;
public:
	Stack();
	bool isempty();
	bool isfull();
	bool push(const Type & item);// add item to stack
	bool pop(Type & item);// pop top into item
};

template <class Type> 
Stack<Type>::Stack()
{
	top = 0;
};
template <class Type>
bool Stack<Type>::isempty()
{
	return top == 0;
}

template <class Type> 
bool Stack<Type>::isfull()
{
	return top == MAX;
}

template <class Type>
bool Stack<Type>::push(const Type & item)
{
	if (top < MAX)
	{
		items[top + t] = item;
		return true;
	}
	else
		return false;
}

template <class Type> 
bool Stack<Type>::pop(Type & item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
		return false;
}
#endif // !STACKTP_H_

14.14 stacktem.cpp

//stacktem.cpp -- testing the template stcak class
#include <iostream>
#include <string>
#include <cctype>
#include "stacktp.h"

using namespace std;

int main()
{
	Stack<string> st;
	char ch;
	string po;
	cout << "Please enter A to add a purchase order,\n" << "P to process a PO, or Q to quit.\n";
	while (cin >> ch && toupper(ch) != 'Q')
	{
		while (cin.get() != '\n')
			continue;
		if (!isalpha(ch))
		{
			cout << "\a";
			continue;
		}
		switch (ch)
		{
		case 'A':
		case 'a': 
			cout << "Enter a PO number to add: ";
			cin >> po;
			if (st.isfull())
				cout << "stack already full\n";
			else
				st.push(po);
			break;
		case 'p':
		case 'P': 
			if (st.isempty())
				cout << "stack already empty\n";
			else
			{
				st.pop(po);
				cout << "PO #" << po << " popped\n";
				break;
			}

		}
		cout << "Please enter A to add apurchase order,\n" << "P to process a PO, or Q to quit.\n";
	}
	cout << "Bye\n";
	return 0;
}

優化棧類模板

14.15 stcktp1.h

//stacktp.h -- a stack template
#ifndef STACKTP1_H_
#define STACKTP1_H_
template <class Type>

class Stack
{
private:
	enum { SIZE = 10 };
	int stacksize;
	Type * items;
	int top;
public:
	explicit Stack(int ss = SIZE);
	Stack(const Stack & st);
	~Stack() { delete[] items; }
	bool isempty() { return top == 0; }
	bool isfull() { return top == stacksize; }
	bool push(const Type & item);// add item to stack
	bool pop(Type & item);// pop top into item
	Stack & operator=(const Stack & st);
};

template <class Type>
Stack<Type>::Stack(const Stack & st)
{
	stacksize = st.stacksize;
	top = st.top;
	items = new Type[stacksize];
	for (int i = 0; i < top; i++)
		items[i] = st.items[i];
};

template <class Type>
bool Stack<Type>::push(const Type & item)
{
	if (top < stacksize)
	{
		items[top++] == item;
		return true;
	}
	else
		return false;
}

template <class Type> 
bool Stack<Type>::pop(Type & item)
{
	if (top > 0)
	{
		item = items[--top];
		return true;
	}
	else
		return false;
}

template <class Type>
Stack<Type> & Stack<Type>::operator=(const Stack<Type> & st)
{
	if (this == &st) 
		return *this; 
	delete[] items; 
	stacksize = st.stacksize;
	top = st.top;
	items = new Type[stacksize]; 
	for (int i = 0; i < top; i++)
		items[i] = st.items[i]; 
	return *this;
}

#endif // !STACKTP1_H_

14.16 stkoptr1.cpp

// stkoptrl.cpp -- testing stack of pointers 
#include <iostream>
#include <cstdlib> 
#include <ctime>
#include "stcktp1.h"

const int Num = 10;

int main()
{
	std::srand(std::time(0)); // randomize rand() 
	std::cout << "Please enter stack size: ";
	int stacksize;
	std::cin >> stacksize;
	// create an empty stack with stacksize slots 
	Stack<const char *> st(stacksize);
		//in basket
		const char *in[Num] = { " 1: Hank Gilgamesh", " 2: Kiki Ishtar",
								" 3: Betty Rocker", " 4: Ian Flagranti",
								" 5: Wolfgang Kibble", " 6: Portia Koop",
								" 7: Joy Almondo", " 8: Xaverie Paprika",
								" 9: Juan Moore", "10: Misha Mache" };
	// out basket
	const char * out[Num];
	int processed = 0;
	int nextin = 0;
	while (processed < Num)
	{
		if (st.isempty())
			st.push(in[nextin++]);
		else if (st.isfull())
			st.pop(out[processed++]);
		else if (std::rand() % 2 && nextin < Num) // 50-50 chance
			st.push(in[nextin++]);
		else
			st.pop(out[processed++]);
	}
	for (int i = 0; i < Num; i++)
		std::cout << out[i] << std::endl;
	std::cout << "Bye\n";
	return 0;

	// for rand(), srand() // for timed
}

陣列模板

14.17 arraytp.h

//arraytp.h -- Array Template
#ifndef ARRAYTP_H_
#define ARRAYTP_H_
#include <iostream>
#include <cstdlib>

template<class T, int n>

class ArrayTp
{
private:
	T ar[n];
public:
	ArrayTp() {};
	explicit ArrayTp(const T & v);
	virtual T &operator[](int i);
	virtual T operator[](int i) const;
};

template <class T, int n>
ArrayTp<T, n>::ArrayTp(const T & v)
{
	for (int i = 0; i < n; i++)
		ar[i] = v;
}

template <class T, int n>
T & ArrayTp<T, n>::operator[](int i)
{
	if (i < 0 || i >= n)
	{
		std::cerr << "Error in array limits: " << i << " is out of range\n";
		exit(EXIT_FAILURE);
	}
	return ar[i];
}

template<class T, int n>
T ArrayTp<T, n>::operator[](int i) const
{

	if (i < 0 || i >= n)
	{
		std::cerr << "Error in array limits: " << i << " is out of range\n";
		exit(EXIT_FAILURE);
	}
	return ar[i];
}
#endif

14.18 twod.cpp

//twod.cpp -- making a 2-d array
#include <iostream>
#include "arraytp.h"

int main(void)
{
	using namespace std;

	ArrayTp<int, 10> sums;
	ArrayTp<double, 10> aves;
	ArrayTp<ArrayTp<int, 5>, 10> twodee;

	int i, j;

	for (i = 0; i < 10; i++)
	{
		sums[i] = 0;
		for (j = 0; j < 5; j++)
		{
			twodee[i][j] = (i + 1)*(j + 1);
			sums[i] += twodee[i][j];
		}
		aves[i] = (double)sums[i] / 10;
	}
	for (i = 0; i < 5; i++)
	{
		for (j = 0; j < 5; j++)
		{
			cout.width(2);
			cout << twodee[i][j] << ' ';
		}
		cout << ": sum = ";
		cout.width(3);
		cout << sums[i] << ", average = " << aves[i] << endl;
	}
	cout << "Done.\n";

	return 0;
}

使用多個型別引數

14.19 pairs.cpp

//pairs.cpp -- defining and using a Pair template
#include <iostream>
#include <string>

template <class T1, class T2>
class Pair
{
private:
	T1 a;
	T2 b;
public:
	T1 & first();
	T2 & second();
	T1 first() const { return a; }
	T2 second() const { return b; }
	Pair(const T1 & aval, const T2 & bval) : a(aval), b(bval) {}
	Pair() {}
};

template<class T1, class T2>
T2 & Pair<T1, T2>::second()
{
	return b;
}

int main()
{
	using namespace std;
	Pair<string, int> ratings[4] =
	{
		Pair<string, int>("Duck", 5),
		Pair<string, int>("Fresco", 4),
		Pair<string, int>("souffle", 5),
		Pair<string, int>("eats", 3)
	};

	int joints = sizeof(ratings) / sizeof(Pair<string, int>);
	cout << "Rating:\t Eatery\n";
	for (int i = 0; i < joints; i++)
		cout << ratings[i].second() << ":\t"
		<< ratings[i].first() << endl;
	cout << "Oops! Revised rating:\n";
	ratings[3].first() = "Bertie's Fab Eats";
	ratings[3].second() = 6;
	cout << ratings[3].second() << ":\t"
		<< ratings[3].first() << endl;
	return 0;
}

成員模板

14.20 tempmemb.cpp

// tempmemb.cpp--- template members
#include <iostream>
using std::cout; 
using std::endl; 
template <typename T> 
class beta
{
private:
	template <typename V> // nested template class member 
	class hold
	{
	private:
		V val;
	public:
		hold(V v = 0) : val(v) {}
		void show() const { cout << val << endl; }
		V Value() const { return val; }
	};
public:
	beta(T t, int i) : q(t), n(i) {}
	template<typename U> // template method
	U blab(U u, T t) { return (n.Value() + q.Value()) * u / t }
	void Show() const { q.show(); n.show(); }
};

int main()
{
	beta<double> guy(3.5, 3); 
	cout << "T was set to double\n"; 
	guy.Show();
	cout << "V was set to T, which is-double, then V was set to int\n";
	cout << guy.blab(10, 2.3) << endl;
	cout << "U was set to int\n";
	cout << guy.blab(10.0, 2.3) << endl;
	cout << "U was set to double\n";
	cout << "Done\n";
	return 0;
}

將模板用作引數

14.21 tempparm.cpp

// tempparm.cpp - templates as parameters 
#include <iostream>
#include "stacktp.h"
template <template <typename T> class Thing > 
class Crab
{
private:
	Thing<int> s1;
	Thing<double> s2; 
public:
	Crab () {};
	// assumes the thing class has pushd and pop() members
	bool push(int a, double x) { return sl.push(a) && s2.push(x); }
	bool pop(int & a, double & x) { return sl.pop(a) && s2.pop(x); }
};

int main()
{
	using std::cout;
	using std::cin;
	using std::endl;
	Crab<Stack> nebula;
	// Stack must match template <typename T> class thing 
	int ni;
	double nb;
	cout << "Enter int double pairs, such as 4 3.5 (0 0 to end):\n";
	while (cin >> ni >> nb && ni > 0 && nb > 0)
	{
		if (!nebula.push(ni, nb))
			break;
	}
	while (nebula.pop(ni, nb))
		cout << ni << ", " << nb << endl;
	cout << "Done.\n";
	return 0;
}

 模板類與友元

14.22 frnd2tmp.cpp

//frnd2tmp.cpp -- template class with non-template friends
#include <iostream>

using namespace std;

template <typename T>
class HasFriend
{
private:
	T item;
	static int ct;
public:
	HasFriend(const T & i) : item(i) {ct++}
	~HasFriend() { ct--; }
	friend void counts();
	friend void reports(HasFriend<T> &);
};

// each specialization has its own static data member 
template <typename T> 
int HasFriend<T>::ct = 0;
// non template friend to all HasFriend<T> classes 
void counts()
{
	cout << "int count: " << HasFriend<int>::ct << "; ";
	cout << " double count: " << HasFriend<double>::ct << endl;
}

//non template . friend: to the HasFriend<int> clans 
void reports(HasFriend<int> & hf)
{
	cout << "HasFriend<int>: " << hf.item << endl;
}

// non-template .friend to the HasFrieiid<dduble> class 
void reports(HasFriend<double> & hf)
{
	cout << "HasFriend<dbuble>: " << hf.item << endl;
}

int main()
{
	cout << "No objects declared: ";
	counts();
	HasFriend<int> hfi1(10); 
	cout << "After hfi1 declared: ";
	counts();
	HasFriend<int> hfi2(20);
	cout << "After hfi2 declared: ";
	counts();
	HasFriend<double> hfdb(10.5);
	cout << "After hfdb declared: ";
	counts();
	reports(hfi1);
	reports(hfi2);
	reports(hfdb);

	return 0;
}

模板類的約束模板友元函式

14.23 tmp2tmp.cpp

// tmp2tmp.cpp -- template friends to a template class 
#include <iostream> 
using std::cout; 
using std::endl;

// template prototypes
template <typename T> void counts();
template <typename T> void report(T &);

// template class 
template <typename TT> 
class HasFriendT
{
private:
	TT item; 
	static int ct; 
public:
	HasFriendT(const TT & i) : item(i) { ct++; }
	~HasFriendT() { ct--; }
	friend void counts<TT>();
	friend void report(HasFriendT<TT> &);
};

template <typename T> 
int HasFriendT<T>::ct = 0;

// template friend functions definitions 
template <typename T> 
void counts()
{
	cout << "template size: " << sizeof(HasFriendT<T>) << ";";
	cout << "template counts(): " << HasFriendT<T>::ct << endl;
}

template <typename T> 
void report(T & hf)
{
	cout << hf.item << endl;
}

int main()
{
	counts<int>();
	HasFriendT<int> hfi1(10);
	HasFriendT<int> hfi2(20);
	HasFriendT<double> hfdb(10.5);
	report(hfi1);	// generate report(HasFriendT<int> &)
	report(hfi2);	// generate report(HasFriendT<int> &)
	report(hfdb);	// generate report(HasFriendT<double> &)
	cout << "counts<int>0 output:\n"; 
	counts<int>();
	cout << "counts<double>() output:\n"; 
	counts<double>();

	return 0;
}

模板類的非約束模板友元函式

14.24  manyfrnd.cpp

// manyfrnd.cpp -- unbound template friend to a template class 
#include <iostream> 
using std::cout; 
using std::endl;

template <typename T> 
class ManyFriend
{
private:
	T item;
public:
	ManyFriend(const T & i) : item(i) {}
	template <typename C, typename D> friend void show2(C &, D &);
};

template <typename C, typename D> void show2(C & c, D & d)
{
	cout << c.item << ", " << d.item << endl;
}

int main()
{
	ManyFriend<int> hfi1(10);
	ManyFriend<int> hfi2(20);
	ManyFriend<double> hfdb(10.5);
	cout << "hfi1, hfi2: ";
	show2(hfi1, hfi2);
	cout << "hfdb, hfi2: ";
	show2(hfdb, hfi2);

	return 0;
}