&); friend istream & operator>>
(istream &,Screen&); public: typedef std::string::size_type index; Screen(): screen(hi * wid,'#'),cursor(0),height(hi),width(wid) {} private: string screen; index cursor; index height,width; }; template
ostream &operator<<(ostream &os,const Screen
&s) { os << "screen: " << s.screen << "\t" << "height: " << s.height << "\t" << "width: " << s.width; return os; } template
istream &operator>>(istream &in,Screen
&s) { in >> s.screen >> s.height >> s.width; if (in) { s.cursor = s.height * s.width; } return in; }
//习题16.42 templateistream &operator>>(istream &in,Queue &q) { Type item; in >> item; q.push(item); return in; }
五、成员模板
任意类都可以拥有本身为类模板或函数模板的成员,这种成员称为成员模板,成员模板不能为虚。
考虑Queue类的复制构造函数:它接受一个形参,是Queue
我们希望定义一个构造函数和一个 assign成员,使容器类型和元素类型都能变化。
在Queue例子中,我们将定义构造函数和 assign成员接受一对在其他序列指明范围的迭代器,这些函数将有一个表示迭代器类型的模板类型形参。
【注意】
标准queue类没有定义这些成员:不支持从其他容器建立queue对象或给 queue对象赋值。我们在这里定义这些成员只是为了举例说明。
1、定义成员模板
模板成员声明看起来像任意模板的声明一样:
templateclass Queue { public: //函数形参是指明要复制元素范围的迭代器 template Queue(Iter beg,Iter end):head(0),tail(0) { copy_elems(beg,end); } template void assign(Iter,Iter); //As Before private: //As Before template void copy_elems(Iter,Iter); };
2、在类外部定义成员模板
当在类外定义成员模板的时候,必须包含两个模板形参表:
1)assign成员:
//T:类模板形参;Iter:成员函数自己的模板形参 templatetemplate void Queue ::assign(Iter beg,Iter end) { destroy(); copy_elems(beg,end); }
2)copy_elems成员:
templatetemplate void Queue ::copy_elems(Iter beg,Iter end) { while (beg != end) { push(*beg); ++ beg; } }
【小心地雷】
因为assign函数删除现在容器中的成员,所以传给assign函数的迭代器有必要引用不同容器中的元素。标准容器的assign成员和迭代器构造函数有相同的限制。
3、成员模板遵循常规访问控制
成员模板遵循与任意其他类成员一样的访问规则。如果成员模板为私有的,则只有该类的成员函数和友元可以访问该成员模板。
4、成员模板和实例化
成员模板只有在程序中使用时才实例化。只是类模板的成员模板实例化比类模板的普通成员函数的实例化要稍微复杂一些,成员模板有两种模板形参:由类定义的和由成员模板本身定义。其中:类模板形参由调用函数的对象的类型确定,成员定义的模板形参的行为与普通函数模板一样。这些形参都通过常规模板实参推断而确定。
理解下面一段程序:
short a[4] = {0,3,6,9};
Queue
qi(a,a + 4);
vector
vi(a,a + 4); qi.assign(vi.begin(),vi.end());
qi的定义将实例化:
void Queue::Queue(short *, short *);
qi的assign成员的实例化:
void Queue::assign(vector ::iterator, vector ::iterator);