12.5 细述使用刻面
类locale包含了诸多刻面(facet)。所有类locale必须包容某些标准刻面。C++标准程序库实例版本均在locale中附加了部分其他刻面。此外,用户还可以自己定义刻面或替换标准刻面。
对于任何类别,如要作为刻面,需要满足以下两个条件:
1)类别F以public形式派生于locale::facet类别。基类主要定义机制,这些机制是针对locale对象内部的引用计数器运用。对于copy构造函数和assignment()操作符声明为pri-vate,禁止外界复制facet,同时禁止对刻面的赋值。
2)类别F必须拥有一个型别为locale::id的公共静态成员,名为id。此成员用于“以某个facet型别为索引,搜寻locale内的一个facet”。之所以要以型别作为索引,主要是要保证型别的安全。内部是普通容器,以整数索引管理facet。
标准刻面不仅需要遵循上述要求,还要遵循部分特殊实例化原则。
此外,标准刻面还应遵循以下原则:
1)所有成员函数均声明为const类型。因为use_facet()返回一个引用指向(const fac-et)。在程序中,对于某个成员函数不能声明为const,否则会失去被调用的可能。
2)对于public函数,不是虚函数。将调用操作委托给一个“保护型(protected)”虚函数,后者的名称类似对应的公用函数,仅仅在前面加上do_。numpunct::truename()会调用numpunct::do_truename()。
对于标准刻面的描述仅限于公用函数(public())。如果需要改变某个facet,应该修改其对应的保护型成员函数。大部分标准刻面均定义了“_byname”版本。该版本均是派生于标准刻面,被用于“根据相应locale名字”生成相应的facet实例。类numpunct_byname多用于针对一个具体的locale产生一个新的numpunct刻面。
诸多“_byname”类别在类locale的“以名称为参数”的构造函数中被作为内部运用。每个标准刻面均有一个对应的名称,相应的_byname类别可用于构造该刻面的实例。