包含对象成员的类
包含:私有部分有一个类。
使用模板类,声明对象时必须指定具体的数据类型。
范例:
#ifndef STUDENTC_H_
#define STUDENTC_H_
#include <iostream>
#include <string>
#include <valarray>
class Student
{
private:
typedef std::valarray<double> ArrayDb;
std::string name; // contained object
ArrayDb scores;
// contained object
// private method for scores output
std::ostream &arr_out(std::ostream &os) const;
public:
Student() : name("Null Student"), scores() {}
Student(const std::string &s)
: name(s), scores() {}
explicit Student(int n) : name("Nully"), scores(n) {}
Student(const std::string &s, int n)
: name(s), scores(n) {}
Student(const std::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 std::string &Name() const;
double &operator[](int i);
double operator[](int i) const;
// friends
// input
friend std::istream &operator>>(std::istream &is, Student &stu);
// 1 word
friend std::istream &getline(std::istream &is, Student &stu); // output
// 1 line
friend std::ostream &operator<<(std::ostream &os, const Student &stu);
};
#endif
类定义中包括:
可以在代码中使用ArrayDb,而不是std::valarray <double>.
typedef放在类定义的私有部分意味着可以Student类的实现中使用它,但是在类外面不能使用。
其中的--个构造函数使用了关键字explicit:
在上述构造函数中,第一个参数表示数组的元素个数,而不是数组中的值,因此将一个构造函数用作int 到Student 的转换函数是没有意义的,所以使用 explicit 关闭隐式转换。如果省略该关键字,则可以编写如下所示的代码:
防止出现手误的错误。
初始化被包含的对象
对于继承的对象,构造函数在成员初始化列表中使用类名来调用特定的基类构造函数。对于成员对象构造函数则使用成员名。例如,最后一个构造函数:
因为该构造函数初始化的是成员对象,而不是继承的对象,所以在初始化列表中使用的是成员名,而不是类名。初始化列表中的每一项都调用与之匹配的构造函数,即name(str)调用String(const char*)构造函数,scores(pd,n)调用ArrayDb(const double*,int)构造函数。
使用被包含对象的接口
被包含的对象的接口不是公有的,但是可以在类方法中使用。
上述代码定义了可由 Student对象调用的方法,该方法内部使用了valarray的方法size()和sumO)。这是因为 scores是一个 valarray 对象,所以它可以调用 valarray 类的成员函数。简而言之,Student对象调用Student 的方法,而后者使用被包含的valarray 对象来调用 valarray 类的方法。
同样可以定义友元函数:
注意,operator<<(ostream& os,const Student&stu)必须是 Student 类的友元函数,这样才能访问 name 成员。另一种方法是,在该函数中使用公有方法Name(),而不是私有数据成员name。
因为 stu.name 是一个 string对象,所以它将调用 operatot<<(ostream&,conststring&)函数,该函数位于 string 类中。
#include "studentc.h"
using std::endl;
using std::istream;
using std::ostream;
using std::string;
// public methods
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];
}
// private method
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;
}
// friend
// use string version of operator>>()
istream &operator>>(istream &is, Student &stu)
{
is >> stu.name;
return is;
}
// use string friend getline(ostream &,const string &)
istream &getline(istream &is, Student &stu)
{
getline(is, stu.name);
return is;
}
// use string version of operator<<()
ostream &operator<<(ostream &os, const Student &stu)
{
os << "Scores for " << stu.name << ":\n";
stu.arr_out(os); // use private method for scores
return os;
}
使用新的student类
#include <iostream>
#include "studentc.h"
using std::cin;
using std::cout;
using std::endl;
void set(Student &sa, int n);
const int pupils = 3;
const int quizzes = 5;
int main()
{
Student ada[pupils] = {Student(quizzes), Student(quizzes), Student(quizzes)};
int i;
for (i = 0; i < pupils; ++i)
set(ada[i], quizzes);
cout << "\nStudent ist:\n";
for (i = 0; i < pupils; ++i)
cout << ada[i].Name() << endl;
cout << "\nResults:";
for (i = 0; i < pupils; ++i)
{
cout << endl
<< ada[i];
cout << "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;
}
运行结果
私有继承
私有继承是has-a关系
公有继承是is-a关系
私有继承关键词private
区别是省略了显式对象名称,直接在内联函数中使用了类名。
对于对象中的对象
私有继承可以使用类名和作用域解析符来调用基类的方法。
使用强制类型转换访问基类对象
#ifndef STUDENTI_H_
#define STUDENTI_H_
#include <iostream>
#include <string>
#include <valarray>
class Student : private std::string, private std::valarray<double>
{
private:
typedef std::valarray<double> ArrayDb;
// contained object
// private method for scores output
std::ostream &arr_out(std::ostream &os) const;
public:
Student() : std::string("Null Student"), ArrayDb() {}
Student(const std::string &s)
: std::string(s), ArrayDb() {}
explicit Student(int n) : std::string("Nully"), ArrayDb(n) {}
Student(const std::string &s, int n)
: std::string(s), ArrayDb(n) {}
Student(const std::string &s, const ArrayDb &a)
: std::string(s), ArrayDb(a) {}
Student(const char *str, const double *pd, int n)
: std::string(str), ArrayDb(pd, n) {}
~Student() {}
double Average() const;
const std::string &Name() const;
double &operator[](int i);
double operator[](int i) const;
// friends
// input
friend std::istream &operator>>(std::istream &is, Student &stu);
// 1 word
friend std::istream &getline(std::istream &is, Student &stu); // output
// 1 line
friend std::ostream &operator<<(std::ostream &os, const Student &stu);
};
#endif
#include "studenti.h"
using std::endl;
using std::istream;
using std::ostream;
using std::string;
// public methods
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);
}
// private method
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;
}
// friend
// use string version of operator>>()
istream &operator>>(istream &is, Student &stu)
{
is >> (string &)stu;
return is;
}
// use string friend getline(ostream &,const string &)
istream &getline(istream &is, Student &stu)
{
getline(is, (string &)stu);
return is;
}
// use string version of operator<<()
ostream &operator<<(ostream &os, const Student &stu)
{
os << "ArrayDb::operator[] for " << (const string &)stu << ":\n";
stu.arr_out(os); // use private method for ArrayDb::operator[]
return os;
}
同样的程序文件
#include <iostream>
#include "studenti.h"
using std::cin;
using std::cout;
using std::endl;
void set(Student &sa, int n);
const int pupils = 3;
const int quizzes = 5;
int main()
{
Student ada[pupils] = {Student(quizzes), Student(quizzes), Student(quizzes)};
int i;
for (i = 0; i < pupils; ++i)
set(ada[i], quizzes);
cout << "\nStudent ist:\n";
for (i = 0; i < pupils; ++i)
cout << ada[i].Name() << endl;
cout << "\nResults:";
for (i = 0; i < pupils; ++i)
{
cout << endl
<< ada[i];
cout << "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;
}
结果和之前相同
包含和私有继承的选择
多重继承
多重继承(MI)表示有多个直接基类的类。
MI的问题:
从两个不同的基类继承同名方法:
#ifndef WORKER0_H_
#define WORKER0_H_
#include <string>
class Worker // an abstract base class
{
private:
std::string fullname;
long id;
public:
Worker() : fullname("no one"), id(0L) {}
Worker(const std::string &s, long n) : fullname(s), id(n) {}
virtual ~Worker() = 0; // pure virtual destructor
virtual void Set();
virtual void Show() const;
};
class Waiter : public Worker
{
private:
int panache;
public:
Waiter() : Worker(), panache(0) {}
Waiter(const std::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 std::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
#include "worker0.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
// Worker methods
// must implement virtual destructor,even if pure
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";
}
// Waiter methods
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";
}
// Singer methods
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;
cin >> voice;
while (cin.get() != '\n')
continue;
}
void Singer::Show() const
{
cout << "Category: singer \n";
Worker::Show();
cout << "Vocal range: " << pv[voice] << endl;
}
#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();
std::cout << std::endl;
}
return 0;
}
在祖先相同时,使用 MI必须引入虚基类,并修改构造函数初始化列表的规则。
修改后的代码
#ifndef WORKERMI_H_
#define WORKERMI_H_
#include <string>
class Worker // an abstract base class
{
private:
std::string fullname;
long id;
protected:
virtual void Data() const;
virtual void Get();
public:
Worker() : fullname("no one"), id(0L) {}
Worker(const std::string &s, long n) : fullname(s), id(n) {}
virtual ~Worker() = 0; // pure virtual destructor
virtual void Set();
virtual void Show() const;
};
class Waiter : virtual public Worker
{
private:
int panache;
protected:
virtual void Data() const;
virtual void Get();
public:
Waiter() : Worker(), panache(0) {}
Waiter(const std::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:
virtual void Data() const;
virtual void Get();
private:
static char *pv[Vtypes];
int voice;
public:
Singer() : Worker(), voice(other) {}
Singer(const std::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;
};
// multiple inheritance
class SingingWaiter : public Singer, public Waiter
{
protected:
void Data() const;
void Get();
public:
SingingWaiter() {};
SingingWaiter(const std::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) {}
void Set();
void Show() const;
};
#endif
#include "workermi.h"
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
// Worker methods
// must implement virtual destructor,even if pure
Worker::~Worker() {}
// protect methods
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 Worker::Set()
{
cout << "Enter worker's name: ";
getline(cin, fullname);
Worker::Get();
Get();
}
void Worker::Show() const
{
cout << "Category: waiter\n";
Worker::Data();
Data();
}
// Waiter methods
void Waiter::Set()
{
cout << "Enter waiter's name:";
Worker::Get();
Get();
}
void Waiter::Show() const
{
cout << "Category: waiter\n";
Worker::Data();
Data();
}
// protect method
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;
}
// Singer methods
char *Singer::pv[] = {"other", "alto", "contralto",
"soprano", "bass", "baritone", "tenor"};
void Singer::Set()
{
cout << "Enter singer's name\n";
Worker::Get();
Get();
}
void Singer::Show() const
{
cout << "Category: singer \n";
Worker::Data();
Data();
}
// protect methods
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;
}
// SingerWaiter methods
void SingingWaiter::Data() const
{
Singer::Data();
Waiter::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();
}
#include <iostream>
#include <cstring>
#include "workermi.h"
const int SIZE = 5;
int main()
{
using std::cin;
using std::cout;
using std::endl;
using std::strchr;
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 enteraw,s,t,or g:";
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;
}
类模板
定义类模板
对于下列类
模板类的开头
template <class Type>
同时将所有的Typedef 改成Type
#ifndef STACKTP_H_
#define STACKTP_H_
template <class Type>
class Stack
{
private:
enum
{
MAX = 10
}; // constant specific to class
Type items[MAX]; // holds stack items
int top;
// index for top stack item
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++] = 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
使用模板类
#include <iostream>
#include <string>
#include <cctype>
#include "stacktp.h"
using std::cin;
using std::cout;
int main()
{
Stack<std::string> st;
char ch;
std::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 a purchase order, \n"
<< "P to process a PO, or Q to quit. \n";
}
cout << "Bye\n";
return 0;
}
只在程序中包含模板不能生成模板类,必须要求实例化。
指针堆栈
使用指针堆栈需要使用指针数组不然容易出错。
#ifndef STACKTP1_H_
#define STACKTP1_H_
template <class Type>
class Stack
{
private:
enum
{
SIZE = 10
};
int stacksize;
// constant specific to class
Type *items; // holds stack items
int top;
// index for top stack item
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);
Stack &operator=(const Stack &st);
};
template <class Type>
Stack<Type>::Stack(int ss) : stacksize(ss), top(0)
{
items = new Type[stacksize];
}
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
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "stacktp1.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);
// int 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++]); // 50-50 chance
else if (std::rand() % 2 && nextin < Num)
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;
}
具有随机特性。
数组模板范例和非类型参数
首先介绍一个允许指定数组大小的简单数组模板。一种方法是在类中使用动态数组和构造函数参数来提供元素数目,最后一个版本的 Stack 模板采用这种方法。另一种方法是使用模板参数来提供常规数组的大小,
#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";
std::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";
std::exit(EXIT_FAILURE);
}
return ar[i];
}
#endif
递归使用模板
#include <iostream>
#include "arraytp.h"
int main(void)
{
using std::cout;
using std::endl;
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 < 10; 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;
}
使用多个类型参数
// 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>
T1 &Pair<T1, T2>::first()
{
return a;
}
template <class Tl, class T2>
T2 &Pair<Tl, T2>::second()
{
return b;
}
int main()
{
using std::cout;
using std::endl;
using std::string;
Pair<string, int> ratings[4] =
{Pair<string, int>("The Purple Duke", 5),
Pair<string, int>("Jake's Frisco Al Fresco", 4),
Pair<string, int>("Mont Souffle", 5),
Pair<string, int>("Gertie's 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() = " Gertie's Fab Eat";
ratings[3].second() = 6;
cout << ratings[3].second() << ":\t"
<< ratings[3].first() << endl;
return 0;
}
模板的具体化
隐式具体化
显式实例化
template class ArrayTP<string,100>;
显式具体化(待补充)
部分具体化(待补充)
成员模板
模板可用作结构,类或模板类的成员。
下列代码实现了模板的嵌套
#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; }
};
hold<T> q;
hold<int> n;
public:
// template object// template object
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);
guy.Show();
cout << guy.blab(10, 2.3) << endl;
cout << "Done\n";
return 0;
}
更改代码
将模板用作参数
下列代码将模板作为参数
#include <iostream>
#include "stacktp.h"
template <template <typename T> class Thing>
class Crab
{1.
private:
Thing<int> s1;
Thing<double> s2;
public:
Crab() {};
bool push(int a, double x) { return s1.push(a) && s2.push(x); }
bool pop(int &a, double &x) { return s1.pop(a) && s2.pop(x); }
};
int main()
{
using std::cin;
using std::cout;
using std::endl;
Crab<Stack> nebula;
int ni;
double nb;
cout << "Enter int double pairs, such as 4 3.5 (0 0 to be 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;
}
模板类和友元
模板的友元分类
- 非模板友元
- 约束模板友元,友元的类型取决于类被实例化的类型
- 非约束模板友元,友元的所有具体化都是类的每一个具体化的友元。
模板类的非模板友元函数
#include <iostream>
using std::cout;
using std::endl;
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> &); // template parameter
};
// specialization
template <typename T>
int HasFriend<T>::ct = 0;
void counts()
{
cout << "int count: " << HasFriend<int>::ct << "; ";
cout << "double count: " << HasFriend<double>::ct << endl;
}
void reports(HasFriend<int> &hf)
{
cout << "HasFriend<int>: " << hf.item << endl;
}
void reports(HasFriend<double> &hf)
{
cout << "HasFriend<double>: " << hf.item << endl;
}
int main()
{
cout << "No objects declared: ";
counts();
HasFriend<int> hfi1(10);
cout << "After fhi1 declared: ";
counts();
HasFriend<int> hfi2(20);
cout << "After fhi2 declared: ";
counts();
HasFriend<double> hfi3(10.5);
cout << "After hfdb declared: ";
counts();
reports(hfi1);
reports(hfi2);
reports(hfi3);
return 0;
}
程序说明:
定义了模板参数:
具体化:
模板类的约束模板友元函数
#include <iostream>
using std::cout;
using std::endl;
// template prototypes
template <typename T>
void counts();
template <typename T>
void reports(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 reports<>(HasFriendT<TT> &); // template parameter
};
// specialization
template <typename T>
int HasFriendT<T>::ct = 0;
template <typename T>
void counts()
{
cout << "template size: " << sizeof(HasFriendT<T>) << "; ";
cout << "template counts: " << HasFriendT<T>::ct << endl;
}
template <typename T>
void reports(T &hf)
{
cout << hf.item << endl;
}
int main()
{
counts<int>();
HasFriendT<int> hfi1(10);
HasFriendT<int> hfi2(20);
HasFriendT<double> hfi3(10.5);
reports(hfi1);
reports(hfi2);
reports(hfi3);
cout << "counts<int>() output: \n";
counts<int>();
cout << "counts<double>() output: \n";
counts<double>();
return 0;
}
这种情况每个T类型都有自己的count函数
因为有定义:
模板类的非约束模板友元函数
约束模板友元函数是在类外面声明的模板的具体化。int 类具体化获得int 函数具体化,依此类推。通过在类内部声明模板,可以创建非约束友元函数,即每个函数具体化都是每个类具体化的友元。对于非约束友元,友元模板类型参数与模板类类型参数是不同的:
#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;
}
其中非约束模板友元函数为