您的位置:首页 > 编程语言 > C语言/C++

Standard C++ Episode 10

2015-08-21 04:30 447 查看
一、为什么要有模板?

将类型参数化,可以实现算法与类型的分离,编写针对类型更加抽象的函数或者类。

二、函数模板

通用定义:

template<typename 类型形参1, ...>

返回类型 函数模板名 (形参表) { ... }

特化定义:

template<>

返回类型 函数模板名<类型实参1, ...> (形参表) { ... }

/* 函数模板(模板函数)练习
* */
#include <iostream>
#include <typeinfo>
#include <cstring>
using namespace std;

template<typename T/*类型形式参数表*/>
//typename关键字声明了类型形式参数表,早期这里采用的关键字是class,早期就直接用关键字class来声明类型形式参数, 在这里class就是typename, typename就是class, 没有区别!
T Max (T x, T y)
{//编译期编译此处时,不进行实际编译,只进行基本的类型检查,当后期有模板的实例要进行编译时,根据实例化时候给出的实际类型参数进行编译,这称为"后期编译"。
//后期编译,在获得实际类型参数时进行编译,也就是说一个模板函数或许在编译期被编译为多个具体的函数。
cout << typeid (T).name () << endl;
return x > y ? x : y;
}

// 模板特化
template<>//缺少后部分编译器会报错,部分容错性比较好的编译器能够自动识别同名于模板函数的函数为其特化。
char* Max<char* /*可以省略,编译器可以根据后边括号中的char*隐式推断出来这里的char**/> (char* x, char* y)
{//当编译期获得实际类型参数是char*时,按照该特化的模板编译。
return strcmp (x, y) > 0 ? x : y;
}
template<typename T>
void foo (void) {
T t;
cout << typeid (t).name () << endl;
}
int main (void) {
cout << "输入两个整数:" << flush;
int nx, ny;
cin >> nx >> ny;
cout << "最大值:" << Max<int/*类型实际参数*/> (nx, ny) << endl;//获得Max的实际类型参数表后进行编译,这叫做"后期编译"。
cout << "输入两个字符串:" << flush;
string sx, sy;
cin >> sx >> sy;
cout << "最大值:" << Max (sx, sy) << endl;//编译器自动推断类型实际参数,最终编译函数string Max(string, string);
cout << "输入两个字符串:" << flush;
foo<int> ();//编译器不能自动推断类型实际参数,必须显式的给出类型实际参数表。
foo<double> ();
foo<string> ();

char cx[256], cy[256];
cin >> cx >> cy;
cout << "最大值:" << Max<char*> (cx, cy) << endl;//编译函数char* Max(chat*, char*);

return 0;
}


三、类模板

通用定义:

template<typename 类型形参1, ...>

class 类模板名 { ... };

全类特化:

template<>

class 类模板名<类型实参1, ...> { ... };

成员特化:

template<>

返回类型 类模板名<类型实参1, ...>::成员函数名 (形参表) { ... }

/*类模板练习
* */
#include <iostream>
#include <cstring>
using namespace std;
// 通用模板
template<typename T>
class Comparator {
public:
Comparator (T x, T y) : m_x (x), m_y (y) {}
T min (void) const {
return m_x < m_y ? m_x : m_y;
}
T max (void) const {
return m_x > m_y ? m_x : m_y;
}
private:
T m_x;
T m_y;
};
/*
// 针对char*的全模板特化
template<>
class Comparator<char*> {
public:
Comparator (char* x, char* y) :
m_x (x), m_y (y) {}
char* min (void) const {
return strcmp (m_x, m_y) < 0 ? m_x : m_y;
}
char* max (void) const {
return strcmp (m_x, m_y) > 0 ? m_x : m_y;
}
private:
char* m_x;
char* m_y;
};
*/
// 针对char*的成员函数特化
template<>
char* Comparator<char*>::min (void) const {
return strcmp (m_x, m_y) < 0 ? m_x : m_y;
}
template<>
char* Comparator<char*>::max (void) const {
return strcmp (m_x, m_y) > 0 ? m_x : m_y;
}
int main (void) {
cout << "输入两个整数:" << flush;
int nx, ny;
cin >> nx >> ny;
Comparator<int> cn (nx, ny);// 编译期使用实际类型参数表进行模板实例化,运行期使用实例化后的类进行对象实例化。
cout << "最小值:" << cn.min () << endl;
cout << "最大值:" << cn.max () << endl;
cout << "输入两个字符串:" << flush;
string sx, sy;
cin >> sx >> sy;
Comparator<string> cs (sx, sy);
cout << "最小值:" << cs.min () << endl;
cout << "最大值:" << cs.max () << endl;
cout << "输入两个字符串:" << flush;
char cx[256], cy[256];
cin >> cx >> cy;
Comparator<char*> cc (cx, cy);
cout << "最小值:" << cc.min () << endl;
cout << "最大值:" << cc.max () << endl;
return 0;
}


四、局部特化

/*
* 模板的局部特化
* */
#include <iostream>
using namespace std;
template<typename T1, typename T2>
class A {
public:
A (void) {
cout << "A<T1,T2>" << endl;
}
};
template<typename T1>
class A<T1, int> {
public:
A (void) {
cout << "A<T1,int>" << endl;
}
};
template<>
class A<int, int> {
public:
A (void) {
cout << "A<int,int>" << endl;
}
};
template<typename T>
class B {
public:
B (void) {
cout << "B<T>" << endl;
}
};
template<typename T>
class B<T*> {
public:
B (void) {
cout << "B<T*>" << endl;
}
};
template<typename T>
class B<T[]> {
public:
B (void) {
cout << "B<T[]>" << endl;
}
};
template<typename T1, typename T2, typename T3>
class C {
public:
C (void) {
cout << "C<T1,T2,T3>" << endl;
}
};
template<typename T1, typename T2>
class C<T1, T2, T2> {
public:
C (void) {
cout << "C<T1,T2,T2>" << endl;
}
};
template<typename T1>
class C<T1, T1*, T1*> {
public:
C (void) {
cout << "C<T1,T1*,T1*>" << endl;
}
};
int main (void) {
// 特化程度高(具体化程度高,模板实例化程度高)的优先
A<double, double> a1;
A<double, int> a2;
A<int, int> a3;
// 针对指针和数组的特化优先
B<char> b1;
B<char*> b2;
B<char[]> b3;
// 匹配度高的特化优先
C<char, short, long> c1;
C<char, short, short> c2;
C<char, char*, char*> c3;
return 0;
}


五、非类型参数和缺省参数

1.非类型参数的实参仅限于常量或者常量表达式。

2.无论类型参数还是非类型参数都可以带有缺省值,而且和函数的缺省参数一样,模板的缺省参数也必须靠右。

#include <iostream>
using namespace std;
template<typename T = int, size_t S = 5>
class Array {
public:
T& operator[] (size_t i) {
return m_array[i];
}
const T& operator[] (size_t i) const {
return const_cast<Array&> (*this) [i];
}
size_t size (void) const {
return S;
}
friend ostream& operator<< (ostream& os,
const Array& arr) {
for (size_t i = 0; i < arr.size (); ++i)
os << '(' << arr.m_array[i] << ')';
return os;
}
private:
T m_array[S];
};
int main (void) {
const /*volatile*/ int x = 3, y = 7;//对于具有常属性的变量,编译器在编译期进行优化,会把常属性的变量替换为常量,以图通过立即数来提高访问效率。通过关键字volatile可以取消编译器的这种优化。
Array<int, x+y> arr;//非类型实际参数只能是常量表达式
for (size_t i = 0; i < arr.size (); ++i)
arr[i] = i;
cout << arr << endl;
Array<Array<int, 4>, 3> m;
for (size_t i = 0; i < m.size (); ++i)
for (size_t j = 0; j < m[i].size (); ++j)
m[i][j] = i * m[i].size () + j;
cout << m << endl;
Array<double> a2;
Array<> a3;
return 0;
}


#include <iostream>
using namespace std;

template<typename T>
class A {
public:
class B {};
};

template<typename T>
void foo (void) {
typename A<T>::B b;//直接写A<T>::B b;编译报错。因编译期初期不会将模板编译成代码,所以A<T>此时还是一个不明的模板类名称,取一个不明模板类作用域里面的B,在编译器进行模板的语法检查时候被编译器报错。可以通过关键字typename来告诉编译器A<T>是后期编译的一个类型名称。
//这里的typename不可以换为class.这里的typename关键字是告诉编译器A<T>::B是个类型名称
}

int main (void) {
foo<int> ();
return 0;
}


六、有关模板的其它问题

1.从模板继承

/*
* 类模板中的继承-从类模板继承
* */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
A (const T& t) : m_t (t) {}
T m_t;
};
template<typename T, typename Y>
class B : public A<T>/*A是模板名称,A<T>是类名称*/ {
public:
B (const T& t, const Y& y) :
A<T> (t), m_y (y) {}
Y m_y;
};
int main (void) {
B<int, string> b (100, "hello");
cout << b.m_t << ' ' << b.m_y << endl;
return 0;
}


2.向模板派生

/*
* 向模板派生
* 例如本例程:基类具体类,派生类是类模板
*
* */
#include <iostream>
using namespace std;
template<typename BASE>
class Shape : public BASE {
public:
void draw (void) const {
BASE::draw ();
}
};
class Rect {
public:
void draw (void) const {
cout << "绘制矩形..." << endl;
}
};
class Circle {
public:
void draw (void) const {
cout << "绘制圆形..." << endl;
}
};
int main (void) {
Shape<Rect> shape1;
shape1.draw ();
Shape<Circle> shape2;
shape2.draw ();
return 0;
}


3.模板中模板成员

1)模板型成员变量

2)模板型成员函数

3)模板型成员类型(内部类)

4.模板型模板实参

/*
*模板型成员变量
*/
#include <iostream>
using namespace std;

template<typename T>
class A {
public:
A (const T& t) : m_t (t) {}
T m_t;
};

template<typename T, typename Y>
class B {
public:
B (const T& t, const Y& y) :
m_a (t), m_y (y) {}
A<T> m_a;
Y m_y;
};

int main (void) {
B<int, string> b (100, "hello");
cout << b.m_a.m_t << ' ' << b.m_y << endl;
return 0;
}


/*
* 模板型成员函数
* */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
A (const T& t) : m_t (t) {}
/*
template<typename Y>
void print (const Y& y) {
cout << m_t << ' ' << y << endl;
}
*/
template<typename Y>
void print (const Y& y);
T m_t;
};
template<typename T>
template<typename Y>
void A<T>::print (const Y& y) {
cout << m_t << ' ' << y << endl;
}
int main (void) {
A<int> a (100);
a.print<string> ("hello");
return 0;
}


/*
* 模板型成员类型(内部类)
*
* */
#include <iostream>
using namespace std;
template<typename T, typename Y>
class A {
public:
A (const T& t, const Y& y) :
m_t (t), m_b (y) {}
/*
template<typename X>
class B {
public:
B (const X& x) : m_x (x) {}
X m_x;
};
*/
template<typename X> class B;//声明模板B
T m_t;
B<Y> m_b;
};
template<typename T, typename Y>
template<typename X>
class A<T, Y>::B {
public:
B (const X& x) : m_x (x) {}
X m_x;
};
int main (void) {
A<int, string> a (100, "hello");
cout << a.m_t << ' ' << a.m_b.m_x << endl;
return 0;
}


/*
* 模板型模板实参(模板作为模板的实参)
*
* */
#include <iostream>
using namespace std;
template<typename T>
class A {
public:
A (const T& t) : m_t (t) {}
T m_t;
};

template<typename X, typename Z,
template<typename T>  class Y/*Y是一个模板*/>//也可以写作template<class X, class Z, template<class T> class Y>
class B {
public:
B (const X& i, const Z& s) :
m_i (i), m_s (s) {}
Y<X> m_i;
Y<Z> m_s;
};
int main (void) {
B<int, string, A> b (100, "hello");
cout << b.m_i.m_t << ' ' << b.m_s.m_t << endl;
return 0;
}


七、容器和迭代器

/*
* 基于双向链表的容器的实现
*
* */
#include <iostream>
#include <stdexcept>
#include <cstring>
using namespace std;
// 双向线性链表容器模板
template<typename T>
class List {
public:
// 构造、析构、拷贝构造、拷贝赋值
List (void) : m_head (NULL), m_tail (NULL) {}
~List (void) {
clear ();
}
List (const List& that) : m_head (NULL),
m_tail (NULL) {
for (Node* node = that.m_head; node;
node = node->m_next)
push_back (node->m_data);
}
List& operator= (const List& that) {
if (&that != this) {
List list (that);
swap (m_head, list.m_head);
swap (m_tail, list.m_tail);
}
return *this;
}
// 获取首元素
T& front (void) {
if (empty ())
throw underflow_error ("链表下溢!");
return m_head->m_data;
}
const T& front (void) const {
return const_cast<List*> (this)->front ();
}
// 向首部压入
void push_front (const T& data) {
m_head = new Node (data, NULL, m_head);
if (m_head->m_next)
m_head->m_next->m_prev = m_head;
else
m_tail = m_head;
}
// 从首部弹出
void pop_front (void) {
if (empty ())
throw underflow_error ("链表下溢!");
Node* next = m_head->m_next;
delete m_head;
m_head = next;
if (m_head)
m_head->m_prev = NULL;
else
m_tail = NULL;
}
// 获取尾元素
T& back (void) {
if (empty ())
throw underflow_error ("链表下溢!");
return m_tail->m_data;
}
const T& back (void) const {
return const_cast<List*> (this)->back ();
}
// 向尾部压入
void push_back (const T& data) {
m_tail = new Node (data, m_tail);
if (m_tail->m_prev)
m_tail->m_prev->m_next = m_tail;
else
m_head = m_tail;
}
// 从尾部弹出
void pop_back (void) {
if (empty ())
throw underflow_error ("链表下溢!");
Node* prev = m_tail->m_prev;
delete m_tail;
m_tail = prev;
if (m_tail)
m_tail->m_next = NULL;
else
m_head = NULL;
}
// 删除所有匹配元素
void remove (const T& data) {
for (Node* node = m_head, *next; node;
node = next) {
next = node->m_next;
if (equal (node->m_data, data)) {
if (node->m_prev)
node->m_prev->m_next =
node->m_next;
else
m_head = node->m_next;
if (node->m_next)
node->m_next->m_prev =
node->m_prev;
else
m_tail = node->m_prev;
delete node;
}
}
}
// 清空
void clear (void) {
for (Node* next; m_head; m_head = next) {
next = m_head->m_next;
delete m_head;
}
m_tail = NULL;
}
// 判空
bool empty (void) const {
return ! m_head && ! m_tail;
}
// 获取大小
size_t size (void) const {
size_t count = 0;
for (Node* node = m_head; node;
node = node->m_next)
++count;
return count;
}
// 插入输出流
friend ostream& operator<< (ostream& os,
const List& list) {
for (Node* node = list.m_head; node;
node = node->m_next)
os << *node;
return os;
}
private:
// 节点
class Node {
public:
Node (const T& data = 0, Node* prev = NULL,
Node* next = NULL) : m_data (data),
m_prev (prev), m_next (next) {}
friend ostream& operator<< (ostream& os,
const Node& node) {
return os << '(' << node.m_data << ')';
}
T m_data; // 数据
Node* m_prev; // 前指针
Node* m_next; // 后指针
};
bool equal (const T& a, const T& b) const {
return a == b;
}
Node* m_head; // 头指针
Node* m_tail; // 尾指针
public:
// 正向迭代器
class Iterator {
public:
Iterator (Node* head = NULL,
Node* tail = NULL, Node* node = NULL) :
m_head (head), m_tail (tail),
m_node (node) {}
bool operator== (const Iterator& it) const {
return m_node == it.m_node;
}
bool operator!= (const Iterator& it) const {
return ! (*this == it);
}
Iterator& operator++ (void) {
if (m_node)
m_node = m_node->m_next;
else
m_node = m_head;
return *this;
}
const Iterator operator++ (int) {
Iterator old = *this;
++*this;
return old;
}
Iterator& operator-- (void) {
if (m_node)
m_node = m_node->m_prev;
else
m_node = m_tail;
return *this;
}
const Iterator operator-- (int) {
Iterator old = *this;
--*this;
return old;
}
T& operator* (void) const {
return m_node->m_data;
}
T* operator-> (void) const {
return &**this;
}
private:
Node* m_head;
Node* m_tail;
Node* m_node;
friend class List;
};
Iterator begin (void) {
return Iterator (m_head, m_tail, m_head);
}
Iterator end (void) {
return Iterator (m_head, m_tail);
}
Iterator insert (Iterator loc, const T& data) {
if (loc == end ()) {
push_back (data);
return Iterator (m_head, m_tail,m_tail);
}
else {
Node* node = new Node (data,
loc.m_node->m_prev, loc.m_node);
if (node->m_prev)
node->m_prev->m_next = node;
else
m_head = node;
node->m_next->m_prev = node;
return Iterator (m_head, m_tail, node);
}
}
Iterator erase (Iterator loc) {
if (loc == end ())
throw invalid_argument ("无效迭代器!");
if (loc.m_node->m_prev)
loc.m_node->m_prev->m_next =
loc.m_node->m_next;
else
m_head = loc.m_node->m_next;
if (loc.m_node->m_next)
loc.m_node->m_next->m_prev =
loc.m_node->m_prev;
else
m_tail = loc.m_node->m_prev;
Node* next = loc.m_node->m_next;
delete loc.m_node;
return Iterator (m_head, m_tail, next);
}
};
// 针对const char*的特化
template<>
bool List<const char*>::equal (const char* const& a,
const char* const& b) const {
return strcmp (a, b) == 0;
}
// 测试用例
int main (void) {
try {
List<int> list1;
list1.push_front (20);
list1.push_front (10);
list1.push_back (30);
list1.push_back (40);
cout << list1 << endl;
cout << list1.front () << ' ' <<
list1.back () << endl;
list1.pop_front ();
list1.pop_back ();
cout << list1 << endl;
++list1.front ();
--list1.back ();
cout << list1 << endl;
list1.push_back (21);
list1.push_back (25);
list1.push_back (21);
list1.push_back (21);
cout << list1 << endl;
list1.remove (21);
cout << list1 << endl;
List<int> list2 = list1;
cout << list2 << endl;
list2.back () = 100;
cout << list2 << endl;
cout << list1 << endl;
list2 = list1;
cout << list2 << endl;
list2.front () = 100;
cout << list2 << endl;
cout << list1 << endl;
cout << list1.size () << endl;
list1.clear ();
cout << list1 << endl;
cout << boolalpha << list1.empty () << endl;
//        List<string> list3;
List<const char*> list3;
list3.push_back ("beijing");
list3.push_back ("tianjin");
list3.push_front ("tianjin");
list3.push_back ("shanghai");
list3.push_back ("beijing");
cout << list3 << endl;
list3.remove (string ("beijing").c_str ());
cout << list3 << endl;
for (List<const char*>::Iterator it =
list3.begin (); it != list3.end ();
++it)
cout << *it << ' ';
cout << endl;
List<const char*>::Iterator it =
list3.begin ();
it++;
it = list3.insert (it, "chongqing");
cout << list3 << endl;
list3.erase (it);
cout << list3 << endl;
}
catch (exception& ex) {
cout << ex.what () << endl;
return -1;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: