⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 use_1194.htm

📁 C++标准库 C++标准库 C++标准库 C++标准库
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<P>Despite its appealing simplicity, however, having just one static country code table might prove too inflexible.  Consider that mnemonics might vary from one locale to another due to different languages.  Maybe mnemonics are not called for, and you really need more extended names associated with the actual country code.</P><P>In order to provide more flexibility, we can build in the ability to work with an arbitrary table.  A pointer to the respective country code table can be provided when a facet object is constructed.  The static table, shown in Figure 16 below, will serve as a default:</P><H4>Figure 16.  Map associating country codes with country names</H4><BR><IMG SRC="images/image16.gif"><P>Since we hold the table as a pointer, we need to pay attention to memory management for the table pointed to.  We will use a flag for determining whether the provided table needs to be deleted when the facet is destroyed.  The following code demonstrates use of the table and its associated flag:</P><PRE>class phone_put: public locale::facet {public:  typedef string string_t;  class prefixMap_t;  static locale::id id;  phone_put( const prefixMap_t* tab=0                         //1           , bool del = false           , size_t refs = 0)           : locale::facet(refs)           , countryCodes_(tab), delete_it_(del)           , myCountryCode_(""), intlPrefix_("")   { if (tab)   {  countryCodes_ = tab;                  delete_it_ = del;   }    else       {  countryCodes_ = &#38;stdCodes_;                 //2                  delete_it_ = false; }  }  string_t put(const string_t&#38; ext,                const string_t&#38; area,                const string_t&#38; cnt) const;  const prefixMap_t* country_codes() const                    //3  { return countryCodes_; }  static const prefixMap_t* std_codes()    { return &#38;stdCodes_; }protected:  phone_put(const string_t&#38; myC, const string_t&#38; intlP          , const prefixMap_t* tab=0, bool del = false          , size_t refs = 0)          : locale::facet(refs)          , countryCodes_(tab), delete_it_(del)          , myCountryCode_(myC), intlPrefix_(intlP)   { ... }  virtual ~phone_put()   { if(delete_it_)      countryCodes_->prefixMap_t::~prefixMap_t();             //4  }  const prefixMap_t* countryCodes_;                           //5  bool delete_it_;                                                 static const prefixMap_t stdCodes_;  const string_t myCountryCode_;  const string_t intlPrefix_;};</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>The constructor is enhanced to take a pointer to the country code table, together with the flag for memory management of the provided table.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>If no table is provided, the static table is installed as a default.</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>For convenience, a function that returns a pointer to the current table is added.</TD></TR><TR VALIGN="top"><TD>//4</TD><TD>The table is deleted if the memory management flags says so.</TD></TR><TR VALIGN="top"><TD>//5</TD><TD>Protected data members are added to hold the pointer to the current country code table, as well as the associated memory management flag.</TD></TR></TABLE><A NAME="1.6.5"><H3>1.6.5 An Example of a Concrete Facet Class</H3></A><P>As mentioned previously, the phone number facet class is intended to serve as a base class.  Let's now present an example of a concrete facet class, the US phone number formatting facet.  It works by default with the static country code table and "US" as its own locality.  It also knows the prefix for dialing foreign numbers from the US.  Here is the class declaration for the facet:</P><PRE>class US_phone_put : public phone_put {public:   US_phone_put( const prefixMap_t* tab=0               , const string_t&#38; myCod = "US"               , bool del = false               , size_t refs = 0)               : phone_put(myCod,"011",tab,del,refs)   { }};</PRE><P>Other concrete facet classes are built similarly.</P><A NAME="1.6.6"><H3>1.6.6 Using Phone Number Facets</H3></A><P>Now that we have laid the groundwork, we will soon be ready to format phone numbers.  Here is an example of how instances of the new facet class can be used:</P><PRE>ostream ofstr("/tmp/out");ostr.imbue(locale(locale::classic(),new US_phone_put));       //1ostr &#60;&#60; phoneNo("Fr","1","60 17 07 16") &#60;&#60; endl;ostr &#60;&#60; phoneNo("US","541","711-PARK") &#60;&#60; endl;ostr.imbue(locale(locale("Fr")                                //2          ,new Fr_phone_put (&#38;myTab,"France")));ostr &#60;&#60; phoneNo("Allemagne","89","636-40938") &#60;&#60; endl;        //3</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>Imbue an output stream with a locale object that has a phone number facet object.  In the example above, it is the US English ASCII locale with a US phone number facet, and </TD></TR><TR VALIGN="top"><TD>//2</TD><TD>a French locale using a French phone number facet with a particular country code table.</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>Output phone numbers using the inserter function.</TD></TR></TABLE><UL><TABLE CELLSPACING=3 CELLPADDING=3><TR VALIGN=top><TD>The output will be:</TD><TD>011-33-1-60170716<BR>(541)711-PARK<BR>19 49 89 636 40938</TD></TR></TABLE></UL><A NAME="1.6.7"><H3>1.6.7 Formatting Phone Numbers</H3></A><P>Even now, however, the implementation of our facet class is incomplete.  We still need to mention how the actual formatting of a phone number will be implemented.  In the example below, it is done by calling two virtual functions, <SAMP>put_country_code()</SAMP> and <SAMP>put_domestic_area_code()</SAMP>:</P><PRE>class phone_put: public locale::facet {public:  // _  string put(const string&#38; ext,              const string&#38; area,              const string&#38; cnt) const;protected:  // _  virtual string_t put_country_code          (const string_t&#38; country) const = 0;  virtual string_t put_domestic_area_code          (const string_t&#38; area) const = 0;};</PRE><P>Note that the functions <SAMP>put_country_code()</SAMP> and <SAMP>put_domestic_area_code()</SAMP> are purely virtual in the base class, and thus must be provided by the derived facet classes.  For the sake of brevity, we spare you here the details of the functions of the derived classes.  For more information, please consult the directory of sample code delivered on disk with this product.</P><A NAME="1.6.8"><H3>1.6.8 Improving the Inserter Function</H3></A><P>Let's turn here to improving our inserter function.  Consider that the country code table might be huge, and access to a country code might turn out to be a time-consuming operation.  We can optimize the inserter function's performance by caching the country code table, so that we can access it directly and thus reduce performance overhead.  </P><A NAME="1.6.8.1"><H4>1.6.8.1 Primitive Caching</H4></A><P>The code below does some primitive caching.  It takes the phone facet object from the stream's locale object and copies the country code table into a static variable.</P><PRE>ostream&#38; operator&#60;&#60;(ostream&#38; os, const phoneNo&#38; pn){   locale loc = os.getloc();   const phone_put&#38; ppFacet = use_facet&#60;phone_put> (loc);     // primitive caching   static prefixMap_t codes = *(ppFacet.country_codes());   // some sophisticated output using the cached codes   ...   return (os);}</PRE><P>Now consider that the locale object imbued on a stream might change, but the cached static country code table does not.  The cache is filled once, and all changes to the stream's locale object have no effect on this inserter function's cache.  That's probably not what we want.  What we do need is some kind of notification each time a new locale object is imbued, so that we can update the cache.</P><A NAME="1.6.8.2"><H4>1.6.8.2 Registration of a Callback Function</H4></A><P>In the following example, notification is provided by a callback function.  The iostreams allow registration of callback functions.  Class <SAMP>ios_base</SAMP> declares:</P><PRE>enum event { erase_event, imbue_event, copyfmt_event };       //1typedef void (*event_callback) (event, ios_base&#38;, int index);void register_callback (event_callback fn, int index);        //2</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>Registered callback functions are called for three events:<BR><BR><UL><LI><P>Destruction of a stream, </P></LI><LI><P>Imbuing a new locale, and</P></LI><LI><P>Copying the stream state.</P></LI></UL></TD></TR><TR VALIGN="top"><TD>//2</TD><TD>The <SAMP>register_callback()</SAMP> function registers a callback function and an index to the stream's <SAMP>parray</SAMP>.  During calls to <SAMP>imbue()</SAMP>, <SAMP>copyfmt()</SAMP> or <SAMP>~ios_base()</SAMP>, the function <SAMP>fn</SAMP> is called with argument <SAMP>index</SAMP>.  Functions registered are called when an event occurs, in opposite order of registration.<BR><BR>The  <SAMP>parray</SAMP> is a static array in base class <SAMP>ios_base</SAMP>.  One can obtain an index to this array via <SAMP>xalloc()</SAMP>, and access the array via <SAMP>pword(index)</SAMP> or <SAMP>iword(index)</SAMP>, as shown in Figure 17 below:</TD></TR></TABLE><UL><H4>Figure 17.  The static array parray</H4><BR><IMG SRC="images/image17.gif"></UL><P>In order to install a callback function that updates our cache, we implement a class that retrieves an index to <SAMP>parray</SAMP> and creates the cache, then registers the callback function in its constructor.  The procedure is shown in the code below:</P><PRE>class registerCallback_t {public:registerCallback_t(ostream&#38; os                  ,ios_base::event_callback fct                  ,prefixMap_t* codes)  {   int index = os.xalloc();                                   //1   os.pword(index) = codes;                                   //2   os.register_callback(fct,index);                           //3  }};</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>An index to the array is obtained via <SAMP>xalloc()</SAMP>.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>The pointer to the code table is stored in the array via<SAMP> pword()</SAMP>.</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>The callback function and the index are registered.</TD></TR></TABLE><P>The actual callback function will later have access to the cache via the index to <SAMP>parray</SAMP>.</P><P>At this point, we still need a callback function that updates the cache each time the stream's locale is replaced.  Such a callback function could look like this:</P><PRE>void cacheCountryCodes(ios_base::event event                      ,ios_base&#38; str,int cache){  if (event == ios_base::imbue_event)                        //1   {      locale loc = str.getloc();      const phone_put&#60;char>&#38; ppFacet =                    use_facet&#60;phone_put&#60;char> > (loc);         //2      *((phone_put::prefixMap_t*) str.pword(cache)) =                    *(ppFacet.country_codes());                //3   }}</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>It checks whether the event was a change of the imbued locale,</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>retrieves the phone number facet from the stream's locale, and</TD></TR><TR VALIGN="top"><TD>//3</TD><TD>stores the country code table in the cache.  The cache is accessible via the stream's <SAMP>parray</SAMP>.</TD></TR></TABLE><A NAME="1.6.8.3"><H4>1.6.8.3 Improving the Inserter</H4></A><P>We now have everything we need to improve our inserter.  It registers a callback function that will update the cache whenever necessary.  Registration is done only once, by declaring a static variable of class <SAMP>registerCallback_t</SAMP>.</P><PRE>ostream&#38; operator&#60;&#60;(ostream&#38; os, const phoneNo&#38; pn){ static phone_put::prefixMap_t codes =    *(use_facet&#60;phone_put>(os.getloc()).country_codes());     //1 static registerCallback_t cache(os,cacheCountryCodes,&#38;codes);//2  // some sophisticated output using the cached codes  ...}</PRE><TABLE CELLPADDING="3"><TR VALIGN="top"><TD>//1</TD><TD>The current country code table is cached.</TD></TR><TR VALIGN="top"><TD>//2</TD><TD>The callback function <SAMP>cacheCountryCodes</SAMP> is registered.</TD></TR></TABLE><BR><HR><A HREF="fac_3537.htm"><IMG SRC="images/prev.gif"></A> <A HREF="booktoc2.htm"><IMG SRC="images/toc.gif"></A><A HREF="str_8843.htm"><IMG SRC="images/next.gif"></A><P>&copy;Copyright 1996, Rogue Wave Software, Inc.</P></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -