Let us now try to implement the phone number facet class. What does this facet need to know?
A facet needs to know its own locality, because a phone number is formatted differently for domestic and international use; for example, a German number looks like (089) / 636-48018 when used in Germany, but it looks like +1-49-89-636-48018 when used internationally.
A facet needs information about the prefix for dialing international numbers; for example, 011 for dialing foreign numbers from the US, or 00 from Germany, or 19 from France.
A facet needs access to a table of all country codes, so that one can enter a mnemonic for the country instead of looking up the respective country code. For example, I would like to say: "This is a phone number somewhere in Japan" without having to know what the country code for Japan is.
The following class declaration for the telephone number formatting facet class is enhanced with data members for the facet object's own locality, and its prefix for international calls (see //2 and //3 in the code below). Adding a table of country codes is omitted for the time being.
class phone_put: public locale::facet { public: typedef string string_t; static locale::id id; phone_put(size_t refs = 0) : locale::facet(refs) , myCountryCode_("") , intlPrefix_("") { } string_t put(const string_t& ext, const string_t& area, const string_t& cnt) const; protected: phone_put( const string_t& myC //1 , const string_t& intlP , size_t refs = 0) : locale::facet(refs) , myCountryCode_(myC) , intlPrefix_(intlP) { } const string_t myCountryCode_; //2 const string_t intlPrefix_; //3 };
Note how this class serves as a base class for the facet classes that really implement a locale-dependent phone number formatting. Hence, the public constructor does not need to be extended, and a protected constructor is added instead (see //1 above).
Let us now deal with the problem of adding the international country codes that were omitted from the previous class declaration. These country codes can be held as a map of strings that associates the country code with a mnemonic for the country's name, as shown in Table 14:
In the following code, we add the table of country codes:
class phone_put: public locale::facet { public: class prefixMap_t : public map<string,string> //1 { public: prefixMap_t() { insert(tab_t(string("US"),string("1"))); insert(tab_t(string("De"),string("49"))); // ... } }; static const prefixMap_t* std_codes() //2 { return &stdCodes_; } protected: static const prefixMap_t stdCodes_; //3 };
Since the table of country codes is a constant table that is valid for all telephone number facet objects, it is added as a static data member stdCodes_ (see //3). The initialization of this data member is encapsulated in a class, prefixMap_t
(see //1). For convenience, a function std_codes() is added to give access to the table (see //2).
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.
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 15 below, serves as a default:
Since we hold the table as a pointer, we need to pay attention to memory management for the table pointed to. We 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:
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_ = &stdCodes_; //2 delete_it_ = false; } } string_t put(const string_t& ext, const string_t& area, const string_t& cnt) const; const prefixMap_t* country_codes() const //3 { return countryCodes_; } static const prefixMap_t* std_codes() { return &stdCodes_; } protected: phone_put(const string_t& myC, const string_t& 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_; };
//1 | The constructor is enhanced to take a pointer to the country code table, together with the flag for memory management of the provided table. |
//2 | If no table is provided, the static table is installed as a default. |
//3 | For convenience, a function that returns a pointer to the current table is added. |
//4 | The table is deleted if the memory management flags says so. |
//5 | Protected data members are added to hold the pointer to the current country code table, as well as the associated memory management flag. |
OEM Edition, ©Copyright 1999, Rogue Wave Software, Inc.
Contact Rogue Wave about documentation or support issues.