《C++Primer PLus 第五版》读书笔记3(七)

2014-11-24 10:39:59 · 作者: · 浏览: 3
可以有隐式实例化、显示实例化和显示具体化,他们统称为具体化(specialization)。模板以通用类型的方式描述类,而具体化是使用具体的类型生成类声明。
1.隐式实例化
一般的永华都是隐式实例化(implicit instantiation),即他们声明一个活多个对象,指出所需的类型,而编译器使用通用模板提供的处方生成具体的类定义
2.显示实例化
当使用关键字template并支出所需类型来声明类时,编译器将生成类声明的显示实例化(explicit insantiation)。声明必须位于模板定义所在的名称空间中。例如,
template class MyArray
将MyArray声明为一个类。在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。
3.显示具体化(explicit specialization)
显示具体化是特定类型(用于替换模板的通用类型)的定义。有时候,可能需要在为特殊类型实例化时,对模板进行修改,使其行为不同。在这种情况下,可以创建显示具体化。例如:
template
class CSortedArray
{};
在排序的时候,使用>操作符来对值进行比较。对于数字,这管用;如果T表示一种类,则只用定义了T::operator>()方法,这也管用;但如果T是有char*表示的字符串,这将不管用。所以需要对其具体化
template<> class CSortedArray
{};
4.部分具体化
c++还允许部分具体化(partial specialization),即部分限制模板的通用性。例如,部分具体化可以给类型参数之一指定具体的类型
template class CPair {};
template class CPair {}:
关键字后面的<>声明的是没有被具体化的类型参数。因此,上述第二个声明将T2具体化为int,但T1保存不变。注意,如果指定所有的类型,则<>内将为空,这将导致显示具体化。
template<> class CPair {};
[cpp]
// testParSpe.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
using namespace std;

template< typename T1, typename T2 >
class Test
{
public:
Test( T1 a, T2 b )
{
m_a = a;
m_b = b;
}
void show()
{
cout << "the a value is:" << m_a << endl;
cout << "the b value is:" << m_b << endl;
}
private:
T1 m_a;
T2 m_b;
};

template< typename T1 >
class Test< T1, int >
{
public:
Test( T1 a, int b )
{
m_a = a;
m_b = b;
}
void show()
{
cout << "this template< typename T1 >, the a value is:" << m_a << endl;
cout << "this template< typename T1 >, the b value is:" << m_b << endl;
}
private:
T1 m_a;
int m_b;
};

int _tmain(int argc, _TCHAR* argv[])
{
Test< double, int > test( 20.1, 4 );
test.show();

return 0;
}


成员模板
C++模板支持的另一个新特性是:模板可用作结构、类或模板类的成员。要完成时限STL的设计,必须要使用这项特性。
[cpp]
// testTemplateFriend.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
using namespace std;
#include "string"

template
class CBeta
{
public:
CBeta( T t, int i ) : q( t ), n( i )
{}
template

U blab( U u, T t )
{
return ( n.Value() + q.Value() ) * u / t;
}
void show() const
{
q.show();
n.show();
}
private:
template
class CHold
{
public:
CHold( V v = 0 ) : val( v ){}
void show() const { cout << val << endl; }
V Value() const { return val; }
private:
V val;
};
CHold q;
CHold n;
};

int _tmain(int argc, _TCHAR* argv[])
{
CBeta quy( 3.5, 3 );
quy.show();
cout << quy.blab( 10, 2.3 ) << endl;
cout << "Done." << endl;


return 0;
}
在这个程序中CHold模板是在私有部分声明的,因此只能在CBeta类中访问他。CBeta类使用CHold模板声明了两个数据成员:
CHold q;
CHold n;
n是基于int类型的CHold对象,而q成员是基于T类型(CBeta模板参数)的CHold对象。

将模板用作参数
模板可以包含类型参数(如typename T)和非类型参数(例如int n)。模板还可以包含本身就是模板的参数。这种参数是模板新增的特性,用于实现STL。
[cpp]
// testTemplateParam.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "iostream"
using namespace std;
#include "string"
#include "ctime"

template
class CStack
{
public:
explicit CStack( int ss = SIZE );
CStack( const CStack& st );
~CStack()
{
if ( items )
{
delete[] items;
}
}
public:
bool isEmpty()
{
return ( 0 == m_nTop );
}
bool isFull()
{
return ( m_StackSize == m_nTop );
}
bool push( const Type& Item );
bool pop( Type& Item );
CStack& operator= ( const CStack& rCStack );
private:
enum { SIZE = 10 };
int m_StackSize;
Type* items;
int m_nTop;
};

template
CStack::CStack( int ss /* = SIZE */ ) : m_StackSize( ss ), m_nTop( 0 )
{
items = new Type[ m_StackSize ];
}

template
CStac