I l@ve RuBoard Previous Section Next Section

Solution

graphics/bulb_icon.gif

The answers to the three questions are as follows.

  1. Is it safe to inherit ci_char_traits from char_traits<char> this way?

    Public inheritance should normally model IS-A / WORKS-LIKE-A as per the Liskov Substitution Principle (LSP). (See Items 22 and 28.) This, however, is one of the rare exceptions to the LSP, because ci_char_traits is not intended to be used polymorphically through a pointer or reference to the base class char_traits<char>. The standard library does not use traits objects polymorphically. In this case, inheritance is used merely for convenience (well, some would say laziness); inheritance is not being used in an object-oriented way.

    On the other hand, the LSP does still apply in another sense: It applies at compile-time, when the derived object must WORK-LIKE-A base object in the ways required by the basic_string template's requirements. In a newsgroup posting, Nathan Myers[2] puts it this way:

    [2] Nathan is a longtime member of the C++ standards committee and the primary author of the standard's locale facility.

    In other words, LSP applies, but only at compile-time, and by the convention we call "requirements lists." I would like to distinguish this case; call it Generic Liskov Substitution Principle (GLSP): Any type (or template) passed as a template argument should conform to the requirements listed for that argument.

    Classes derived from iterator tags and traits classes, then, are subject to GLSP, but classical LSP considerations (for example, virtual destructor, and so forth) may or may not apply, depending on whether run-time polymorphic behaviors are in the signature specified in the requirements list.

    So, in short, this inheritance is safe, because it conforms to GLSP (if not LSP). However, the main reason I used it here was not for convenience (to avoid writing all the other char_traits<char> baggage), but to demonstrate what's different梩hat we had to change only four operations to get the effect we want.

    The reason behind this first question was to get you to think about several things: (1) the proper uses (and improper abuses) of inheritance; (2) the implications of the fact that there are only static members; (3) the fact that char_traits objects are never used polymorphically.

  2. Why does the following code fail to compile?

    
    
    ci_string s = "abc"; 
    
    
    cout << s << endl;
    
    
    

    Hint: From 21.3.7.9 [lib.string.io] in the C++ standard, the declaration of operator<< for basic_string is specified as:

    
    
    template<class charT, class traits, class Allocator> 
    
    
    basic_ostream<charT, traits>&
    
    
    operator<<(basic_ostream<charT, traits>& os,
    
    
               const basic_string<charT,traits,Allocator>& str);
    
    
    

    Answer: Notice first that cout is actually a basic_ostream<char, char_traits<char> >. Then we can spot the problem: operator<< for basic_string is templated and all, but it's specified only for insertion into a basic_ostream with the same "char type" and "traits type" as the string. That is, the standard operator<< will let you output a ci_string to a basic_ostream<char, ci_char_traits>, which isn't what cout is, even though ci_char_traits inherits from char_traits<char> in the above solution.

    There are two ways to resolve this: Define operator<<() and operator>>() for ci_strings yourself, or tack on ".c_str()" to use operator<<( const char* ) if your application's strings don't have embedded nulls:

    
    
    cout << s.c_str() << endl; 
    
    
    
  3. What about using other operators (for example, +, +=, =) and mixing strings and ci_strings as arguments? For example:

    
    
    string    a = "aaa"; 
    
    
    ci_string b = "bbb";
    
    
    string    c = a + b;
    
    
    

Again, there are two ways to deal with this: Either define your own operator+() functions, or tack on ".c_str()" to use operator+( const char* ):



string    c = a + b.c_str(); 


    I l@ve RuBoard Previous Section Next Section