转载自:http://hi.baidu.com/nicker2010/item/a92b38eb4f918d3087d9deeb
所有标准库版本的locale中都必须包含某些标准的facet
除此之外,用户可以安装属于自己的facet,或者替换标准的facet
我们怎么产生自己的facet呢?
任何一个类型F,只要满足一下两个条件,就可以作为facet:
1. F以public形式派生自locale::facet.
facet主要定义了一些机制,共locale对象内部的引用计数器使用。
此外还将拷贝构造和拷贝复制函数声明为private,
禁止外界拷贝facet,也禁止外界对facet赋值
2. F必须拥有一个型别为locale::id的public static member,名为id.
此成员用来“以某个facet型别为索引,搜索locale之内的一个facet”
下面是CodeBlocks中facet的源码(id的实现在locale中):
class locale::facet
{
private:
friend class locale;
friend class locale::_Impl;
mutable _Atomic_word _M_refcount;
static __c_locale _S_c_locale;
static const char _S_c_name[2];
#ifdef __GTHREADS
static __gthread_once_t _S_once;
#endif
static void _S_initialize_once();
protected:
explicit facet(size_t __refs = 0) throw() : _M_refcount(__refs ? 1 : 0)
{ }
virtual ~facet();
static void _S_create_c_locale(__c_locale& __cloc, const char* __s,
__c_locale __old = 0);
static __c_locale _S_clone_c_locale(__c_locale& __cloc);
static void _S_destroy_c_locale(__c_locale& __cloc);
static __c_locale _S_get_c_locale();
static const char* _S_get_c_name();
private:
inline void _M_add_reference() const throw()
{ __gnu_cxx::__atomic_add(&_M_refcount, 1); }
inline void _M_remove_reference() const throw()
{
if (__gnu_cxx::__exchange_and_add(&_M_refcount, -1) == 1)
{
try
{ delete this; }
catch (...)
{ }
}
}
///私有的拷贝构造和拷贝复制函数
facet(const facet&);
facet& operator=(const facet&);
};
标准facet不仅仅遵循上述两条机制,还遵循一些特殊原则。
如果能做到这些原则,还是好处多多。这些原则包括:
1. 所有的成员函数均声明为const.
2. 所有的public成员函数均不是虚函数,而是将调用操作委托给一个protected函数,
后者的命名类似于对应的public函数,只不过在前面家霍桑do_
如numpunct::truename会调用numpunct::do_truename()
因此,如想改变某个facet,应该改写其对应的protected函数
下面是numpunct类的源码,来源于MSDN,从中也可以看到上面说的两条原则:
template<class E>
class numpunct : public locale::facet
{
public:
typedef E char_type;
typedef basic_string<E> string_type;
explicit numpunct(size_t refs = 0);
E decimal_point() const;
E thousands_sep() const;
string grouping() const;
string_type truename() const;
string_type falsename() const;
static locale::id id;
protected:
~numpunct();
virtual E do_decimal_point() const;
virtual E do_thousands_sep() const;
virtual string do_grouping() const;
virtual string_type do_truename() const;
virtual string_type do_falsename() const;
}
大部分标准facet都定义了一个"_byname"版本。这个版本派生自标准的facet。
被用来根据locale名称产生出相应的facet。
如class numpunct_byname被用来针对一个有名称的locale产生一个numpunct facet