完整目录、平台简介、安装环境及版本:参考《21天学C++ 概览》
十九、模板
19.1 模板的定义和实现
#include <iostream>
const int DefaultSize = 10;
class Animal
{
public:
Animal(int);
Animal();
~Animal() {}
int GetWeight() const { return itsWeight; }
void Display() const { std::cout << itsWeight; }
private:
int itsWeight;
};
Animal::Animal(int weight):
itsWeight(weight)
{}
Animal::Animal():
itsWeight(0)
{}
template <class T> //模板声明
class Array{
public:
Array(int itsSize = DefaultSize); //构造函数
Array(const Array &rhs); //复制构造函数
~Array() { delete [] pType; } //析构函数
Array& operator=(const Array&); //赋值函数
T& operator[](int offSet) { return pType[offSet]; } //取值
const T& operator[](int offSet) const
{ return pType[offSet]; }
int GetSize() const { return itsSize; }
private:
T *pType;
int itsSize;
};
template <class T>
Array<T>::Array(int size):
itsSize(size)
{
pType = new T[size];
// the constructors of the type you are creating
// should set a default value
}
template <class T>
Array<T>::Array(const Array &rhs)
{
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i<itsSize; i++)
pType[i] = rhs[i];
}
template <class T>
Array<T>& Array<T>::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
delete [] pType;
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i<itsSize; i++)
pType[i] = rhs[i];
return *this;
}
int main(){
Array<int> theArray; // 整型数组
Array<Animal> theZoo; // 类型数组
Animal *pAnimal;
for (int i = 0; i < theArray.GetSize(); i++) {
theArray[i] = i*2;
pAnimal = new Animal(i*3);
theZoo[i] = *pAnimal;
delete pAnimal;
}
for (int j = 0; j < theArray.GetSize(); j++) {
std::cout << "theArray[" << j << "]:\t";
std::cout << theArray[j] << "\t\t";
std::cout << "theZoo[" << j << "]:\t";
theZoo[j].Display();
std::cout << std::endl;
}
return 0;
}
执行结果如下:
theArray[0]: 0 theZoo[0]: 0
theArray[1]: 2 theZoo[1]: 3
theArray[2]: 4 theZoo[2]: 6
theArray[3]: 6 theZoo[3]: 9
theArray[4]: 8 theZoo[4]: 12
theArray[5]: 10 theZoo[5]: 15
theArray[6]: 12 theZoo[6]: 18
theArray[7]: 14 theZoo[7]: 21
theArray[8]: 16 theZoo[8]: 24
theArray[9]: 18 theZoo[9]: 27
请按任意键继续. . .
19.2 模板函数
#include <iostream>
using namespace std;
template<class T>
void swap(T left, T right){
cout<<left<<"\t"<<right<<endl;
T temp;
temp = left;
left = right;
right = temp;
cout<<left<<"\t"<<right<<endl;
}
int main(){
swap(1, 2);
swap(1.1, 2.2);
return 0;
}
执行结果如下:
1 2
2 1
1.1 2.2
2.2 1.1
请按任意键继续. . .
19.3 C++ STL
19.3.1 标准模板库 STL
一个基于模板的容器类库,包括链表、队列、列表和堆栈,还包括许多常用的算法,如排序、查找等;
19.3.2 容器
容器是包容其他对象的对象;
STL容器类有两种类型:顺序和关联
- 顺序容器:提供对其他成员成员或元素的顺序和随机访问;
- 关联容器:是经过优化按关键值访问它们的元素;
19.3.3 常用顺序容器:vector
类似数组,提供经过优化来对其元素按下标进行快速访问的容器;
容器可必要时自我增长,自我扩容;
其内部元素用new()创建,用运算符delete()释放,即用户须为自己的类提供显示默认构造函数;
- 如:vector<int> vInts;
- 如: vector<flost> vFloats;
- 如:vector<Student> vStudents(50);创建能容纳50个对象的容器,访为则用vStudent[0]等下标访问;
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#include <vector>
class Student{
public:
Student(); //显示定义构造函数
Student(const string& name, const int age); //重载构造函数
Student(const Student& rhs); //复制构造函数
~Student(); //析构函数
void SetName(const string& name);
string GetName() const;
void SetAge(const int age);
int GetAge() const;
Student& operator=(const Student& rhs); //赋值函数
friend ostream& operator<<(ostream& os, const Student& rhs); //输出
};
Student::Student()
: itsName("New Student"), itsAge(16)
{}
Student::Student(const string& name, const int age)
: itsName(name), itsAge(age)
{}
Student::Student(const Student& rhs)
: itsName(rhs.GetName()), itsAge(rhs.GetAge())
{}
Student::~Student()
{}
void Student::SetName(const string& name)
{
itsName = name;
}
string Student::GetName() const
{
return itsName;
}
void Student::SetAge(const int age)
{
itsAge = age;
}
int Student::GetAge() const
{
return itsAge;
}
Student& Student::operator=(const Student& rhs)
{
itsName = rhs.GetName();
itsAge = rhs.GetAge();
return *this;
}
ostream& operator<<(ostream& os, const Student& rhs)
{
os << rhs.GetName() << " is " << rhs.GetAge() << " years old";
return os;
}
template<class T>
void ShowVector(const vector<T>& v);
typedef vector<Student> SchoolClass;
int main(){
Student Harry;
Student Sally("Sally", 15);
Student Bill("Bill", 17);
Student Peter("Peter", 16);
SchoolClass EmptyClass;
cout << "EmptyClass:" << endl;
ShowVector(EmptyClass);//输出函数
SchoolClass GrowingClass(3);//构造函数
cout << "GrowingClass(3):" << endl;
ShowVector(GrowingClass);
GrowingClass[0] = Harry;
GrowingClass[1] = Sally;
GrowingClass[2] = Bill;
cout << "GrowingClass(3) after assigning students:" << endl;
ShowVector(GrowingClass);//赋值函数
GrowingClass.push_back(Peter);//复制构造函数
cout << "GrowingClass() after added 4th student:" << endl;
ShowVector(GrowingClass);
GrowingClass[0].SetName("Harry");
GrowingClass[0].SetAge(18);
cout << "GrowingClass() after Set\n:";
ShowVector(GrowingClass);
return 0;
}
template<class T> void ShowVector(const vector<T>& v){//模板参数函数
cout << “max_size() = ” << v.max_size();//容器中最大元素数目
cout << "\tsize() = " << v.size(); //
cout << “\tcapacity() = ” << v.capacity(); //编译器内分配容器,倍数增加
cout << "\t" << (v.empty()? "empty": "not empty");
cout << endl;
for (int i = 0; i < v.size(); ++i)
cout << v[i] << endl; //调用输出函数,直接输出类对象
}
执行结果如下:
EmptyClass:
max_size() = 119304647 size() = 0 capacity() = 0 empty
GrowingClass(3):
max_size() = 119304647 size() = 3 capacity() = 3 not empty
New Student is 16 years old
New Student is 16 years old
New Student is 16 years old
GrowingClass(3) after assigning students:
max_size() = 119304647 size() = 3 capacity() = 3 not empty
New Student is 16 years old
Sally is 15 years old
Bill is 17 years old
GrowingClass() after added 4th student:
max_size() = 119304647 size() = 4 capacity() = 4 not empty
New Student is 16 years old
Sally is 15 years old
Bill is 17 years old
Peter is 16 years old
GrowingClass() after Set
:max_size() = 119304647 size() = 4 capacity() = 4 not empty
Harry is 18 years old
Sally is 15 years old
Bill is 17 years old
Peter is 16 years old
请按任意键继续. . .
19.3.4 常用顺序容器:如list
list用于提供对元素的频繁插入或删除进行优化的容器;
list是用双向链表实现的,其中每个节点即和前一个节点链接又和下一个节点链接;
链接通常是指针实现的,标准列表容器类使用一个叫多重指针iterator的方法;
- 成员函数begin返回指向列表中的第一个节点的多重指针;
- 成员函数end返回最后一个即诶但的后面一个节点的多种指针
- 成员函数push_front、pop_front、push_back、pop_back;
#include <iostream>
#include <list>
using namespace std;
typedef list<int> IntegerList;
int main()
{
IntegerList intList;
for (int i = 1; i <= 10; ++i)
intList.push_back(i * 2);
for (IntegerList::const_iterator ci = intList.begin();
ci != intList.end(); ++ci)
cout << *ci << " ";
return 0;
}
执行结果如下:
2 4 6 8 10 12 14 16 18 20 请按任意键继续. . .
19.3.5 堆栈:如stack:后进先出
- 堆栈是一个可以在尾端增长和收缩的连续分配区域;
- 堆栈中的元素只能从后面访问或删除;
- 可以容纳任何元素,但前提是所有元素必须是同一类型;
19.3.6 队列:如stack:先进先出
队列是在一端增加,另一端取出;
19.3.7 关联容器
可以对元素进行快速随机访问,包括映射、多重映射、集合、多重集合;
- 映射:键值唯一,(key, value);其中key唯一;
- 多重映射:没有唯一限制的映射类,多个元素可以有相同的键值;
- 集合:和映射类似,差别是元素不是(key, value),一个元素就是唯一键;
- 多重集合:允许双重键值的集合类;
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Student
{
public:
Student();
Student(const string& name, const int age);
Student(const Student& rhs);
~Student();
void SetName(const string& name);
string GetName() const;
void SetAge(const int age);
int GetAge() const;
Student& operator=(const Student& rhs);
private:
string itsName;
int itsAge;
};
Student::Student()
: itsName("New Student"), itsAge(16)
{}
Student::Student(const string& name, const int age)
: itsName(name), itsAge(age)
{}
Student::Student(const Student& rhs)
: itsName(rhs.GetName()), itsAge(rhs.GetAge())
{}
Student::~Student()
{}
void Student::SetName(const string& name)
{
itsName = name;
}
string Student::GetName() const
{
return itsName;
}
void Student::SetAge(const int age)
{
itsAge = age;
}
int Student::GetAge() const
{
return itsAge;
}
Student& Student::operator=(const Student& rhs)
{
itsName = rhs.GetName();
itsAge = rhs.GetAge();
return *this;
}
ostream& operator<<(ostream& os, const Student& rhs)
{
os << rhs.GetName() << " is " << rhs.GetAge() << " years old";
return os;
}
template<class T, class A>
void ShowMap(const map<T, A>& v); // display map properties
typedef map<string, Student> SchoolClass;
int main()
{
Student Harry("Harry", 18);
Student Sally("Sally", 15);
Student Bill("Bill", 17);
Student Peter("Peter", 16);
SchoolClass MathClass;
MathClass[Harry.GetName()] = Harry;
MathClass[Sally.GetName()] = Sally;
MathClass[Bill.GetName()] = Bill;
MathClass[Peter.GetName()] = Peter;
cout << "MathClass:" << endl;
ShowMap(MathClass);
cout << "We know that " << MathClass["Bill"].GetName()
<< " is " << MathClass["Bill"].GetAge()
<< " years old" << endl;
return 0;
}
template<class T, class A>
void ShowMap(const map<T, A>& v)
{
for (map<T, A>::const_iterator ci = v.begin();
ci != v.end(); ++ci)
cout << ci->first << ": " << ci->second << endl;
cout << endl;
}
执行结果如下:
MathClass:
Bill: Bill is 17 years old
Harry: Harry is 18 years old
Peter: Peter is 16 years old
Sally: Sally is 15 years old
We know that Bill is 17 years old
请按任意键继续. . .
19.4 算法类
标准库提供了大约60中标准算法来执行最基本、最常见的容器运算:如for_each算法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
class Print
{
public:
void operator()(const T& t)
{
cout << t << " ";
}
};
int main()
{
Print<int> DoPrint;
vector<int> vInt(5);
for (int i = 0; i < 5; ++i)
vInt[i] = i * 3;
cout << "for_each()" << endl;
for_each(vInt.begin(), vInt.end(), DoPrint);
cout << endl;
return 0;
}
执行结果如下:
for_each()
0 3 6 9 12
请按任意键继续. . .
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
template<class T>
class Print
{
public:
void operator()(const T& t)
{
cout << t << " ";
}
};
int main()
{
Print<int> DoPrint;
vector<int> vInt(10);
fill(vInt.begin(), vInt.begin() + 5, 1);
fill(vInt.begin() + 5, vInt.end(), 2);
for_each(vInt.begin(), vInt.end(), DoPrint);
cout << endl << endl;
return 0;
}
执行结果如下:
1 1 1 1 1 2 2 2 2 2
请按任意键继续. . .