Docstoc

C Programming Language_ch11

Document Sample
C   Programming Language_ch11 Powered By Docstoc
					________________________________________
________________________________________________________________________________________________________________________________________________________________




                                   11
________________________________________
________________________________________________________________________________________________________________________________________________________________




                                                                                   Operator Overloading

                                                                                               When I use a word it means just what
                                                                                         I choose it to mean – neither more nor less.
                                                                                                                  – Humpty Dumpty



        Notation — operator functions — binary and unary operators — predefined meanings
        for operators — user-defined meanings for operators — operators and namespaces — a
        complex type — member and nonmember operators — mixed-mode arithmetic —
        initialization — copying — conversions — literals — helper functions — conversion
        operators — ambiguity resolution — friends — members and friends — large objects —
        assignment and initialization — subscripting — function call — dereferencing — incre-
        ment and decrement — a string class — advice — exercises.




11.1 Introduction [over.intro]
Every technical field – and most nontechnical fields – have developed conventional shorthand
notation to make convenient the presentation and discussion involving frequently-used concepts.
For example, because of long acquaintance
        x+y z
        x y*z
is clearer to us than
        mu lt ip ly    by    an d ad d th e re su lt to
        m ul ti pl y y b y z a nd a dd t he r es ul t t o x
It is hard to overestimate the importance of concise notation for common operations.
     Like most languages, C++ supports a set of operators for its built-in types. However, most con-
cepts for which operators are conventionally used are not built-in types in C++, so they must be rep-
resented as user-defined types. For example, if you need complex arithmetic, matrix algebra, logic
signals, or character strings in C++, you use classes to represent these notions. Defining operators




       The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
            Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
262       Operator Overloading                                                              Chapter 11



for such classes sometimes allows a programmer to provide a more conventional and convenient
notation for manipulating objects than could be achieved using only the basic functional notation.
For example,
      cl as s co mp le x
      c la ss c om pl ex {               // very simplified complex
               do ub le re im
              d ou bl e r e, i m;
      pu bl ic
      p ub li c:
               co mp le x(d ou bl e r, do ub le i) re r) im i)
              c om pl ex do ub le r d ou bl e i : r e(r , i m(i { }
               co mp le x op er at or co mp le x)
              c om pl ex o pe ra to r+(c om pl ex ;
               co mp le x op er at or co mp le x)
              c om pl ex o pe ra to r*(c om pl ex ;
      };

                                                                            co mp le x
defines a simple implementation of the concept of complex numbers. A c om pl ex is represented by
a pair of double-precision floating-point numbers manipulated by the operators + and *. The pro-
                  co mp le x: op er at or       co mp le x: op er at or
grammer defines c om pl ex :o pe ra to r+() and c om pl ex :o pe ra to r*() to provide meanings for +
                                                            co mp le x, b+c           b.o pe ra to r+(c
and *, respectively. For example, if b and c are of type c om pl ex b c means b op er at or c).
                                                             co mp le x
We can now approximate the conventional interpretation of c om pl ex expressions:
       vo id f()
       v oi d f
       {
              co mp le x     co mp le x(1 3.1
              c om pl ex a = c om pl ex 1, 3 1);
              co mp le x     co mp le x(1 2, 2)
              c om pl ex b = c om pl ex 1.2 2 ;
              co mp le x     b;
              c om pl ex c = b
                 b+c
             a = b c;
                 b+c a;
             b = b c*a
                 a*b co mp le x(1 2)
             c = a b+c om pl ex 1,2 ;
      }

                                                                   b=b c*a           b=(b c)*a
The usual precedence rules hold, so the second statement means b b+(c a), not b b+c a.
   Many of the most obvious uses of operator overloading are for concrete types (§10.3). How-
ever, the usefulness of user-defined operators is not restricted to concrete types. For example, the
design of general and abstract interfaces often leads to the use of operators such as ->, [], and ().


11.2 Operator Functions [over.oper]
Functions defining meanings for the following operators (§6.2) can be declared:
       +           -           *           /          %           ^           &
       |           ~           !           =          <           >           +=
       -=          *=          /=          %=         ^=          &=          |=
       <<          >>          >>=         <<=        ==          !=          <=
       >=          &&          ||          ++         --          ->*         ,
       ->          []          ()          ne w
                                           n ew       n ew
                                                      ne w[]      de le te
                                                                  d el et e   de le te
                                                                              d el et e[]

The following operators cannot be defined by a user:
   :: (scope resolution; §4.9.4, §10.2.4),
   . (member selection; §5.7), and
   .* (member selection through pointer to function; §15.5).




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.2                                                                  Operator Functions      263



They take a name, rather than a value, as their second operand and provide the primary means of
referring to members. Allowing them to be overloaded would lead to subtleties [Stroustrup,1994].
    It is not possible to define new operator tokens, but you can use the function-call notation when
this set of operators is not adequate. For example, use p owpo w(), not **. These restrictions may
seem Draconian, but more flexible rules can easily lead to ambiguities. For example, defining an
operator ** to mean exponentiation may seem an obvious and easy task at first glance, but think
again. Should ** bind to the left (as in Fortran) or to the right (as in Algol)? Should the expres-
      a**p
sion a p be interpreted as a        p)
                               a*(*p or as (a a)**(p p)?
                                                        op er at or
    The name of an operator function is the keyword o pe ra to r followed by the operator itself; for
           op er at or
example, o pe ra to r<<. An operator function is declared and can be called like any other function.
A use of the operator is only a shorthand for an explicit call of the operator function. For example:
     vo id f(c om pl ex a, co mp le x b)
     v oi d f co mp le x a c om pl ex b
     {
            co mp le x         b;
            c om pl ex c = a + b                   // shorthand
            co mp le x     a.o pe ra to r+(b
            c om pl ex d = a op er at or b);       // explicit call
     }

                                 co mp le x,
Given the previous definition of c om pl ex the two initializers are synonymous.

11.2.1 Binary and Unary Operators [over.binary]
A binary operator can be defined by either a nonstatic member function taking one argument or a
                                                                            aa bb
nonmember function taking two arguments. For any binary operator @, a a@b b can be interpreted as
       aa op er at or bb         op er at or aa bb
either a a.o pe ra to r@(b b) or o pe ra to r@(a a,b b). If both are defined, overload resolution (§7.4)
determines which, if any, interpretation is used. For example:
     cl as s
     c la ss X {
     pu bl ic
     p ub li c:
              vo id op er at or in t)
             v oi d o pe ra to r+(i nt ;
              X(i nt
             X in t);
     };
     vo id op er at or X,X
     v oi d o pe ra to r+(X X);
     vo id op er at or X,d ou bl e)
     v oi d o pe ra to r+(X do ub le ;
     vo id f(X a)
     v oi d f X a
     {
            a+1
            a 1;          // a.operator+(1)
            1+a
            1 a;          // ::operator+(X(1),a)
            a+1 0;
            a 1.0         // ::operator+(a,1.0)
     }

A unary operator, whether prefix or postfix, can be defined by either a nonstatic member function
taking no arguments or a nonmember function taking one argument. For any prefix unary operator
    aa                               aa op er at or         op er at or aa
@, @a a can be interpreted as either a a.o pe ra to r@() or o pe ra to r@(a a). If both are defined, over-
load resolution (§7.4) determines which, if any, interpretation is used. For any postfix unary opera-
        aa                                     aa op er at or in t)        op er at or aa in t). This is
tor @, a a@ can be interpreted as either a a.o pe ra to r@(i nt or o pe ra to r@(a a,i nt
explained further in §11.11. If both are defined, overload resolution (§7.4) determines which, if




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
264       Operator Overloading                                                                Chapter 11



any, interpretation is used. An operator can be declared only for the syntax defined for it in the
grammar (§A.5). For example, a user cannot define a unary % or a ternary +. Consider:

       cl as s
       c la ss X {
               // members (with implicit ‘this’ pointer):
             X* op er at or
             X o pe ra to r&();         // prefix unary & (address of)
               op er at or X)
             X o pe ra to r&(X ;        // binary & (and)
               op er at or    in t)
             X o pe ra to r++(i nt ;    // postfix increment (see §11.11)
               op er at or X,X
             X o pe ra to r&(X X);      // error: ternary
               op er at or
             X o pe ra to r/();         // error: unary /
       };
       // nonmember functions :
      X    op er at or X)
           o pe ra to r-(X ;            // prefix unary minus
      X    op er at or X,X
           o pe ra to r-(X X);          // binary minus
      X    op er at or    X&,i nt
           o pe ra to r--(X in t);      // postfix decrement
      X    op er at or
           o pe ra to r-();             // error: no operand
      X    op er at or X,X X)
           o pe ra to r-(X X,X ;        // error: ternary
      X    op er at or X)
           o pe ra to r%(X ;            // error: unary %


Operator [] is described in §11.8, operator () in §11.9, operator -> in §11.10, operators ++ and
-- in §11.11, and the allocation and deallocation operators in §6.2.6.2, §10.4.11, and §15.6.

11.2.2 Predefined Meanings for Operators [over.predefined]

Only a few assumptions are made about the meaning of a user-defined operator. In particular,
op er at or op er at or        op er at or         op er at or
o pe ra to r=, o pe ra to r[], o pe ra to r(), and o pe ra to r-> must be nonstatic member functions; this
ensures that their first operands will be lvalues (§4.9.6).
    The meanings of some built-in operators are defined to be equivalent to some combination of
                                                                              a       a+=1
other operators on the same arguments. For example, if a is an int, ++a means a 1, which in turn
         a=a 1.
means a a+1 Such relations do not hold for user-defined operators unless the user happens to
                                                                                       Z: op er at or
define them that way. For example, a compiler will not generate a definition of Z :o pe ra to r+=()
                            Z: op er at or           Z: op er at or
from the definitions of Z :o pe ra to r+() and Z :o pe ra to r=().
    Because of historical accident, the operators = (assignment), & (address-of), and , (sequencing;
§6.2.2) have predefined meanings when applied to class objects. These predefined meanings can
be made inaccessible to general users by making them private:

       cl as s
       c la ss X {
       pr iv at e:
       p ri va te
                vo id op er at or co ns t X&)
                v oi d o pe ra to r=(c on st X ;
                vo id op er at or
                v oi d o pe ra to r&();
                vo id op er at or co ns t X&)
                v oi d o pe ra to r,(c on st X ;
                // ...
       };




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.2.2                                                   Predefined Meanings for Operators   265


     vo id f(X a,
     v oi d f X a X     b)
                        b
     {
            a=b b;       // error: operator= private
            &aa;         // error: operator& private
            a,b
            a b;         // error: operator, private
     }

Alternatively, they can be given new meanings by suitable definitions.

11.2.3 Operators and User-Defined Types [over.user]

An operator function must either be a member or take at least one argument of a user-defined type
                            ne w      de le te
(functions redefining the n ew and d el et e operators need not). This rule ensures that a user cannot
change the meaning of an expression unless the expression contains an object of a user-defined
type. In particular, it is not possible to define an operator function that operates exclusively on
pointers. This ensures that C++ is extensible but not mutable (with the exception of operators =, &,
and , for class objects).
    An operator function intended to accept a basic type as its first operand cannot be a member
                                                                  aa             2: aa 2
function. For example, consider adding a complex variable a a to the integer 2 a a+2 can, with a
                                                        aa op er at or 2),      2+a a
suitably declared member function, be interpreted as a a.o pe ra to r+(2 but 2 aa cannot because
                  in t                                2.o pe ra to r+(a a).
there is no class i nt for which to define + to mean 2 op er at or aa Even if there were, two dif-
                                                          2+a a       aa 2.
ferent member functions would be needed to cope with 2 aa and a a+2 Because the compiler does
not know the meaning of a user-defined +, it cannot assume that it is commutative and so interpret
2+a a aa 2.
2 aa as a a+2 This example is trivially handled using nonmember functions (§11.3.2, §11.5).
    Enumerations are user-defined types so that we can define operators for them. For example:
     en um Da y su n, mo n, tu e, we d, th u, fr i, sa t
     e nu m D ay { s un m on t ue w ed t hu f ri s at };
     Da y& op er at or    Da y& d)
     D ay o pe ra to r++(D ay d
     {
          re tu rn       sa t==d   su n Da y(d 1)
          r et ur n d = (s at d) ? s un : D ay d+1 ;
     }

Every expression is checked for ambiguities. Where a user-defined operator provides a possible
interpretation, the expression is checked according to the rules in §7.4.

11.2.4 Operators in Namespaces [over.namespace]

An operator is either a member of a class or defined in some namespace (possibly the global name-
space). Consider this simplified version of string I/O from the standard library:
     na me sp ac e st d
     n am es pa ce s td {                 // simplified std
           cl as s os tr ea m
           c la ss o st re am {
                   // ...
                   os tr ea m& op er at or   co ns t ch ar
                   o st re am o pe ra to r<<(c on st c ha r*);
           };
           ex te rn os tr ea m co ut
           e xt er n o st re am c ou t;




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
266       Operator Overloading                                                               Chapter 11


             cl as s st ri ng
             c la ss s tr in g {
                     // ...
             };
             os tr ea m& op er at or   os tr ea m&, c on st s tr in g&);
             o st re am o pe ra to r<<(o st re am   co ns t st ri ng
      }
      in t ma in
      i nt m ai n()
      {
             ch ar          He ll o";
            c ha r* p = "H el lo
            st d: st ri ng         wo rl d";
            s td :s tr in g s = "w or ld
            st d: co ut                         \n
            s td :c ou t << p << ", " << s << "!\ n";
      }

                           He ll o, wo rl d!                                                st d
Naturally, this writes out H el lo w or ld But why? Note that I didn’t make everything from s td
accessible by writing:
       us in g na me sp ac e st d;
       u si ng n am es pa ce s td

                    st d:             st ri ng       co ut
Instead, I used the s td : prefix for s tr in g and c ou t. In other words, I was at my best behavior and
didn’t pollute the global namespace or in other ways introduce unnecessary dependencies.
                                                 ch ar                   st d: os tr ea m,
    The output operator for C-style strings (c ha r*) is a member of s td :o st re am so by definition
       st d: co ut
       s td :c ou t << p

means
       st d: co ut op er at or     p)
       s td :c ou t.o pe ra to r<<(p

         st d: os tr ea m                                            st d: st ri ng
However, s td :o st re am doesn’t have a member function to output a s td :s tr in g, so
       st d: co ut
       s td :c ou t << s

means
       op er at or    st d: co ut s)
       o pe ra to r<<(s td :c ou t,s

Operators defined in namespaces can be found based on their operand types just like functions can
                                                                 co ut                 st d,   st d
be found based on their argument types (§8.2.6). In particular, c ou t is in namespace s td so s td is
considered when looking for a suitable definition of <<. In that way, the compiler finds and uses:
       st d: op er at or    st d: os tr ea m&, c on st s td :s tr in g&)
       s td :o pe ra to r<<(s td :o st re am   co ns t st d: st ri ng

                           x@y
For a binary operator @, x y where x is of type X and y is of type Y is resolved like this:
                                                                           op er at or
   [1] If X is a class, determine whether class X or a base of X defines o pe ra to r@ as a member; if
       so, that is the @ to try to use.
   [2] Otherwise,
                                                                  x@y
       – look for declarations of @ in the context surrounding x y; and
                                           N,                             N;
       – if X is defined in namespace N look for declarations of @ in N and
                                          M,
       – if Y is defined in namespace M look for declarations of @ in M   M.
                       op er at or                                           N,        M,
   If declarations of o pe ra to r@ are found in the surrounding context, in N or in M we try to use
   those operators.
                                            op er at or
In either case, declarations for several o pe ra to r@s may be found and overload resolution rules




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.2.4                                                               Operators in Namespaces   267



(§7.4) are used to find the best match, if any. This lookup mechanism is applied only if the opera-
tor has at least one operand of a user-defined type. Therefore, user-defined conversions (§11.3.2,
                                         ty pe de f
§11.4) will be considered. Note that a t yp ed ef name is just a synonym and not a user-defined type
(§4.9.7).


11.3 A Complex Number Type [over.complex]
The implementation of complex numbers presented in the introduction is too restrictive to please
anyone. For example, from looking at a math textbook we would expect this to work:
     vo id f()
     v oi d f
     {
            co mp le x     co mp le x(1 2)
            c om pl ex a = c om pl ex 1,2 ;
            co mp le x     3;
            c om pl ex b = 3
            co mp le x     a+2 3;
            c om pl ex c = a 2.3
            co mp le x     2+b
            c om pl ex d = 2 b;
            co mp le x       b-c
            c om pl ex e = -b c;
                c*2 c;
            b = c 2*c
     }

In addition, we would expect to be provided with a few additional operators, such as == for com-
                                                                                  si n()     sq rt
parison and << for output, and a suitable set of mathematical functions, such as s in and s qr t().
          co mp le x
    Class c om pl ex is a concrete type, so its design follows the guidelines from §10.3. In addition,
                                                                                  co mp le x
users of complex arithmetic rely so heavily on operators that the definition of c om pl ex brings into
play most of the basic rules for operator overloading.

11.3.1 Member and Nonmember Operators [over.member]
I prefer to minimize the number of functions that directly manipulate the representation of an
object. This can be achieved by defining only operators that inherently modify the value of their
first argument, such as +=, in the class itself. Operators that simply produce a new value based on
the values of its arguments, such as +, are then defined outside the class and use the essential opera-
tors in their implementation:
     cl as s co mp le x
     c la ss c om pl ex {
              do ub le re im
             d ou bl e r e, i m;
     pu bl ic
     p ub li c:
              co mp le x& op er at or  co mp le x a)
             c om pl ex o pe ra to r+=(c om pl ex a ;   // needs access to representation
             // ...
     };
     co mp le x op er at or co mp le x a, co mp le x b)
     c om pl ex o pe ra to r+(c om pl ex a c om pl ex b
     {
            co mp le x
            c om pl ex r = a a;
            re tu rn        b;
            r et ur n r += b // access representation through +=
     }

Given these declarations, we can write:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
268     Operator Overloading                                                               Chapter 11



       vo id f(c om pl ex x, co mp le x y, co mp le x z)
       v oi d f co mp le x x c om pl ex y c om pl ex z
       {
              co mp le x r1 x+y z;
              c om pl ex r 1 = x y+z // r1 = operator+(x,operator+(y,z))
              co mp le x r2 x;
              c om pl ex r 2 = x       // r2 = x
              r2
              r 2 += yy;               // r2.operator+=(y)
              r2
              r 2 += zz;               // r2.operator+=(z)
       }

                                                                 r1     r2
Except for possible efficiency differences, the computations of r 1 and r 2 are equivalent.
    Composite assignment operators such as += and *= tend to be simpler to define than their
‘‘simple’’ counterparts + and *. This surprises most people at first, but it follows from the fact that
three objects are involved in a + operation (the two operands and the result), whereas only two
objects are involved in a += operation. In the latter case, run-time efficiency is improved by elimi-
nating the need for temporary variables. For example:

       in li ne co mp le x& co mp le x: op er at or    co mp le x a)
       i nl in e c om pl ex c om pl ex :o pe ra to r+=(c om pl ex a
       {
                re       a.r e;
                r e += a re
                im        a.i m;
                i m += a im
                re tu rn th is
                r et ur n *t hi s;
       }

does not require a temporary variable to hold the result of the addition and is simple for a compiler
to inline perfectly.
    A good optimizer will generate close to optimal code for uses of the plain + operator also.
                                                                                         co mp le x,
However, we don’t always have a good optimizer and not all types are as simple as c om pl ex so
§11.5 discusses ways of defining operators with direct access to the representation of classes.

11.3.2 Mixed-Mode Arithmetic [over.mixed]

To cope with

       co mp le x     2+b
       c om pl ex d = 2 b;

we need to define operator + to accept operands of different types. In Fortran terminology, we
need mixed-mode arithmetic. We can achieve that simply by adding appropriate versions of the
operators:

       cl as s co mp le x
       c la ss c om pl ex {
               do ub le re im
               d ou bl e r e, i m;

       pu bl ic
       p ub li c:
                co mp le x& op er at or  co mp le x a)
               c om pl ex o pe ra to r+=(c om pl ex a {
                       re      a.r e;
                      r e += a re
                       im       a.i m;
                      i m += a im
                       re tu rn th is
                      r et ur n *t hi s;
               }




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.3.2                                                          Mixed-Mode Arithmetic    269


           co mp le x& op er at or   do ub le a)
           c om pl ex o pe ra to r+=(d ou bl e a {
                  re
                  r e += a a;
                  re tu rn th is
                  r et ur n *t hi s;
           }
           // ...
     };
     co mp le x op er at or co mp le x a, co mp le x b)
     c om pl ex o pe ra to r+(c om pl ex a c om pl ex b
     {
            co mp le x
            c om pl ex r = a a;
            re tu rn        b;
            r et ur n r += b // calls complex::operator+=(complex)
     }
     co mp le x op er at or co mp le x a, do ub le b)
     c om pl ex o pe ra to r+(c om pl ex a d ou bl e b
     {
            co mp le x
            c om pl ex r = a a;
            re tu rn        b;
            r et ur n r += b // calls complex::operator+=(double)
     }
     co mp le x op er at or do ub le a, co mp le x b)
     c om pl ex o pe ra to r+(d ou bl e a c om pl ex b
     {
            co mp le x
            c om pl ex r = b b;
            re tu rn        a;
            r et ur n r += a // calls complex::operator+=(double)
     }

            do ub le                                                              co mp le x.
Adding a d ou bl e to a complex number is a simpler operation than adding a c om pl ex This is
                                                      do ub le
reflected in these definitions. The operations taking d ou bl e operands do not touch the imaginary
part of a complex number and thus will be more efficient.
    Given these declarations, we can write:

     vo id f(c om pl ex x, co mp le x y)
     v oi d f co mp le x x c om pl ex y
     {
            co mp le x r1 x+y
            c om pl ex r 1 = x y; // calls operator+(complex,complex)
            co mp le x r2 x+2
            c om pl ex r 2 = x 2; // calls operator+(complex,double)
            co mp le x r3 2+x
            c om pl ex r 3 = 2 x; // calls operator+(double,complex)
     }



11.3.3 Initialization [over.ctor]

                                                 co mp le x
To cope with assignments and initialization of c om pl ex variables with scalars, we need a conver-
                                                         co mp le x.
sion of a scalar (integer or floating-point number) to a c om pl ex For example:

     co mp le x     3;
     c om pl ex b = 3 // should mean b.re=3, b.im=0

A constructor taking a single argument specifies a conversion from its argument type to the
constructor’s type. For example:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
270     Operator Overloading                                                                  Chapter 11



       cl as s co mp le x
       c la ss c om pl ex {
                do ub le re im
               d ou bl e r e, i m;
       pu bl ic
       p ub li c:
                co mp le x(d ou bl e r) re r) im 0)
               c om pl ex do ub le r :r e(r , i m(0 { }
               // ...
       };

The constructor specifies the traditional embedding of the real line in the complex plane.
   A constructor is a prescription for creating a value of a given type. The constructor is used
when a value of a type is expected and when such a value can be created by a constructor from the
value supplied as an initializer or assigned value. Thus, a constructor requiring a single argument
need not be called explicitly. For example,

       co mp le x     3;
       c om pl ex b = 3

means

       co mp le x     co mp le x(3
       c om pl ex b = c om pl ex 3);

A user-defined conversion is implicitly applied only if it is unique (§7.4). See §11.7.1 for a way of
specifying constructors that can only be explicitly invoked.
    Naturally, we still need the constructor that takes two doubles, and a default constructor initial-
        co mp le x     0,0
izing a c om pl ex to (0 0) is also useful:

      cl as s co mp le x
      c la ss c om pl ex {
               do ub le re im
              d ou bl e r e, i m;
      pu bl ic
      p ub li c:
               co mp le x() : r e(0 , i m(0 { }
              c om pl ex        re 0) im 0)
               co mp le x(d ou bl e r) re r) im 0)
              c om pl ex do ub le r : r e(r , i m(0 { }
               co mp le x(d ou bl e r, do ub le i) re r) im i)
              c om pl ex do ub le r d ou bl e i : r e(r , i m(i { }
              // ...
      };

Using default arguments, we can abbreviate:

       cl as s co mp le x
       c la ss c om pl ex {
                do ub le re im
               d ou bl e r e, i m;
       pu bl ic
       p ub li c:
                co mp le x(d ou bl e  0, do ub le    0) re r) im i)
               c om pl ex do ub le r =0 d ou bl e i =0 : r e(r , i m(i { }
               // ...
       };

When a constructor is explicitly declared for a type, it is not possible to use an initializer list (§5.7,
§4.9.5) as the initializer. For example:

       co mp le x z1
       c om pl ex z 1 = { 3 };         // error: complex has a constructor
       co mp le x z2      3,
       c om pl ex z 2 = { 3 4 };       // error: complex has a constructor




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.3.4                                                                              Copying   271



11.3.4 Copying [over.copy]
                                                     co mp le x
In addition to the explicitly declared constructors, c om pl ex by default gets a copy constructor
defined (§10.2.5). A default copy constructor simply copies all members. To be explicit, we could
equivalently have written:
     cl as s co mp le x
     c la ss c om pl ex {
              do ub le re im
             d ou bl e r e, i m;
     pu bl ic
     p ub li c:
              co mp le x(c on st co mp le x& c) re c.r e) im c.i m)
             c om pl ex co ns t c om pl ex c : r e(c re , i m(c im { }
             // ...
     };

However, for types where the default copy constructor has the right semantics, I prefer to rely on
that default. It is less verbose than anything I can write, and people should understand the default.
Also, compilers know about the default and its possible optimization opportunities. Furthermore,
writing out the memberwise copy by hand is tedious and error-prone for classes with many data
members (§10.4.6.3).
    I use a reference argument for the copy constructor because I must. The copy constructor
defines what copying means – including what copying an argument means – so writing
     co mp le x: co mp le x(c om pl ex c) re c.r e) im c.i m)
     c om pl ex :c om pl ex co mp le x c : r e(c re , i m(c im { } // error

is an error because any call would have involved an infinite recursion.
                                  co mp le x
    For other functions taking c om pl ex arguments, I use value arguments rather than reference
arguments. Here, the designer has a choice. From a user’s point of view, there is little difference
                                  co mp le x                                co ns t co mp le x&
between a function that takes a c om pl ex argument and one that takes a c on st c om pl ex argument.
This issue is discussed further in §11.6.
    In principle, copy constructors are used in simple initializations such as
     co mp le x     2;
     c om pl ex x = 2                   // create complex(2); then initialize x with it
     co mp le x     co mp le x(2 0)
     c om pl ex y = c om pl ex 2,0 ;    // create complex(2,0); then initialize y with it

However, the calls to the copy constructor are trivially optimized away. We could equivalently
have written:
     co mp le x x(2
     c om pl ex x 2);       // initialize x by 2
     co mp le x y(2 0)
     c om pl ex y 2,0 ;     // initialize x by (2,0)

                               co mp le x,
For arithmetic types, such as c om pl ex I like the look of the version using = better. It is possible to
restrict the set of values accepted by the = style of initialization compared to the ()style by making
                                                                        ex pl ic it
the copy constructor private (§11.2.2) or by declaring a constructor e xp li ci t (§11.7.1).
    Similar to initialization, assignment of two objects of the same class is by default defined as
                                                                       co mp le x: op er at or
memberwise assignment (§10.2.5). We could explicitly define c om pl ex :o pe ra to r= to do that.
                                   co mp le x
However, for a simple type like c om pl ex there is no reason to do so. The default is just right.
    The copy constructor – whether user-defined or compiler-generated – is used not only for the
initialization of variables, but also for argument passing, value return, and exception handling (see
§11.7). The semantics of these operations is defined to be the semantics of initialization (§7.1,
§7.3, §14.2.1).




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
272     Operator Overloading                                                              Chapter 11



11.3.5 Constructors and Conversions [over.conv]
We defined three versions of each of the four standard arithmetic operators:
      co mp le x op er at or co mp le x,c om pl ex
      c om pl ex o pe ra to r+(c om pl ex co mp le x);
      co mp le x op er at or co mp le x,d ou bl e)
      c om pl ex o pe ra to r+(c om pl ex do ub le ;
      co mp le x op er at or do ub le co mp le x)
      c om pl ex o pe ra to r+(d ou bl e,c om pl ex ;
      // ...
This can get tedious, and what is tedious easily becomes error-prone. What if we had three alterna-
tives for the type of each argument for each function? We would need three versions of each
single-argument function, nine versions of each two-argument function, twenty-seven versions of
each three-argument function, etc. Often these variants are very similar. In fact, almost all variants
involve a simple conversion of arguments to a common type followed by a standard algorithm.
    The alternative to providing different versions of a function for each combination of arguments
                                               co mp le x
is to rely on conversions. For example, our c om pl ex class provides a constructor that converts a
do ub le       co mp le x.
d ou bl e to a c om pl ex Consequently, we could simply declare only one version of the equality
              co mp le x:
operator for c om pl ex
       bo ol op er at or     co mp le x,c om pl ex
       b oo l o pe ra to r==(c om pl ex co mp le x);
      vo id f(c om pl ex
      v oi d f co mp le x   x, co mp le x y)
                            x c om pl ex y
      {
             x==y
             x y;           // means operator==(x,y)
             x==3
             x 3;           // means operator==(x,complex(3))
             3==y
             3 y;           // means operator==(complex(3),y)
      }
There can be reasons for preferring to define separate functions. For example, in some cases the
conversion can impose overheads, and in other cases, a simpler algorithm can be used for specific
argument types. Where such issues are not significant, relying on conversions and providing only
the most general variant of a function – plus possibly a few critical variants – contains the combi-
natorial explosion of variants that can arise from mixed-mode arithmetic.
    Where several variants of a function or an operator exist, the compiler must pick ‘‘the right’’
variant based on the argument types and the available (standard and user-defined) conversions.
Unless a best match exists, an expression is ambiguous and is an error (see §7.4).
    An object constructed by explicit or implicit use of a constructor is automatic and will be
destroyed at the first opportunity (see §10.4.10).
    No implicit user-defined conversions are applied to the left-hand side of a . (or a ->). This is
the case even when the . is implicit. For example:
       vo id g(c om pl ex z)
       v oi d g co mp le x z
       {
              3+z
              3 z;                     // ok: complex(3)+z
              3.o pe ra to r+=(z ;
              3 op er at or    z)      // error: 3 is not a class object
              3+=z
              3 z;                     // error: 3 is not a class object
       }
Thus, you can express the notion that an operator requires an lvalue as their left-hand operand by
making that operator a member.




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.3.6                                                                             Literals    273



11.3.6 Literals [over.literals]

                                                                        1.2     12 e3
It is not possible to define literals of a class type in the sense that 1 2 and 1 2e 3 are literals of type
do ub le
d ou bl e. However, literals of the basic types can often be used instead if class member functions are
used to provide an interpretation for them. Constructors taking a single argument provide a general
mechanism for this. When constructors are simple and inline, it is quite reasonable to think of con-
                                                                                   co mp le x(3
structor invocations with literal arguments as literals. For example, I think of c om pl ex 3) as a lit-
             co mp le x,
eral of type c om pl ex even though technically it isn’t.

11.3.7 Additional Member Functions [over.additional]

                                   co mp le x
So far, we have provided class c om pl ex with constructors and arithmetic operators only. That is
not quite sufficient for real use. In particular, we often need to be able to examine the value of the
real and imaginary parts:

     cl as s co mp le x
     c la ss c om pl ex {
              do ub le re im
             d ou bl e r e, i m;
     pu bl ic
     p ub li c:
              do ub le re al    co ns t re tu rn re
             d ou bl e r ea l() c on st { r et ur n r e; }
              do ub le im ag     co ns t re tu rn im
             d ou bl e i ma g() c on st { r et ur n i m; }
             // ...
     };

                                 co mp le x, re al    im ag                                co mp le x,
Unlike the other members of c om pl ex r ea l() and i ma g() do not modify the value of a c om pl ex
                         co ns t.
so they can be declared c on st
           re al        im ag
    Given r ea l() and i ma g(), we can define all kinds of useful operations without granting them
                                         co mp le x.
direct access to the representation of c om pl ex For example:

     in li ne bo ol op er at or      co mp le x a, co mp le x b)
     i nl in e b oo l o pe ra to r==(c om pl ex a c om pl ex b
     {
              re tu rn a.r ea l()==b re al && a im ag
              r et ur n a re al      b.r ea l()                  b.i ma g()
                                                    a.i ma g()==b im ag ;
     }

Note that we need only to be able to read the real and imaginary parts; writing them is less often
needed. If we must do a ‘‘partial update,’’ we can:

     vo id f(c om pl ex z, do ub le d)
     v oi d f co mp le x& z d ou bl e d
     {
            // ...
                co mp le x(z re al    d)
            z = c om pl ex z.r ea l(),d ; // assign d to z.im
     }

A good optimizer generates a single assignment for that statement.

11.3.8 Helper Functions [over.helpers]

                                                co mp le x
If we put all the bits and pieces together, the c om pl ex class becomes:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
274     Operator Overloading                                                             Chapter 11



       cl as s co mp le x
       c la ss c om pl ex {
                do ub le re im
               d ou bl e r e, i m;
       pu bl ic
       p ub li c:
                co mp le x(d ou bl e  0, do ub le    0) re r) im i)
               c om pl ex do ub le r =0 d ou bl e i =0 : r e(r , i m(i { }
             do ub le re al     co ns t re tu rn re
             d ou bl e r ea l() c on st { r et ur n r e; }
             do ub le im ag      co ns t re tu rn im
             d ou bl e i ma g() c on st { r et ur n i m; }
             co mp le x& op er at or   co mp le x)
             c om pl ex o pe ra to r+=(c om pl ex ;
             co mp le x& op er at or   do ub le
             c om pl ex o pe ra to r+=(d ou bl e);
             // – =, *=, and /=
      };

In addition, we must provide a number of helper functions:
      co mp le x op er at or co mp le x,c om pl ex
      c om pl ex o pe ra to r+(c om pl ex co mp le x);
      co mp le x op er at or co mp le x,d ou bl e)
      c om pl ex o pe ra to r+(c om pl ex do ub le ;
      co mp le x op er at or do ub le co mp le x)
      c om pl ex o pe ra to r+(d ou bl e,c om pl ex ;
      // – , *, and /
      co mp le x op er at or co mp le x)
      c om pl ex o pe ra to r-(c om pl ex ; // unary minus
      co mp le x op er at or co mp le x)
      c om pl ex o pe ra to r+(c om pl ex ; // unary plus
      bo ol op er at or     co mp le x,c om pl ex
      b oo l o pe ra to r==(c om pl ex co mp le x);
      bo ol op er at or     co mp le x,c om pl ex
      b oo l o pe ra to r!=(c om pl ex co mp le x);
      is tr ea m& op er at or   is tr ea m&,c om pl ex
      i st re am o pe ra to r>>(i st re am co mp le x&); // input
      os tr ea m& op er at or    os tr ea m&,c om pl ex
      o st re am o pe ra to r<<(o st re am co mp le x); // output

                         re al      im ag
Note that the members r ea l() and i ma g() are essential for defining the comparisons. The defini-
                                                                   re al        im ag
tion of most of the following helper functions similarly relies on r ea l() and i ma g().
    We might provide functions to allow users to think in terms of polar coordinates:
       co mp le x po la r(d ou bl e rh o, do ub le th et a)
       c om pl ex p ol ar do ub le r ho d ou bl e t he ta ;
       co mp le x co nj co mp le x)
       c om pl ex c on j(c om pl ex ;
      do ub le ab s(c om pl ex
      d ou bl e a bs co mp le x);
      do ub le ar g(c om pl ex
      d ou bl e a rg co mp le x);
      do ub le no rm co mp le x)
      d ou bl e n or m(c om pl ex ;
      do ub le re al co mp le x)
      d ou bl e r ea l(c om pl ex ;    // for notational convenience
      do ub le im ag co mp le x)
      d ou bl e i ma g(c om pl ex ;    // for notational convenience

Finally, we must provide an appropriate set of standard mathematical functions:
      co mp le x ac os co mp le x)
      c om pl ex a co s(c om pl ex ;
      co mp le x as in co mp le x)
      c om pl ex a si n(c om pl ex ;
      co mp le x at an co mp le x)
      c om pl ex a ta n(c om pl ex ;
      // ...

From a user’s point of view, the complex type presented here is almost identical to the
co mp le x<d ou bl e>         co mp le x>
c om pl ex do ub le found in <c om pl ex in the standard library (§22.5).




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.4                                                                       Conversion Operators   275



11.4 Conversion Operators [over.conversion]
Using a constructor to specify type conversion is convenient but has implications that can be unde-
sirable. A constructor cannot specify
    [1] an implicit conversion from a user-defined type to a basic type (because the basic types are
         not classes), or
    [2] a conversion from a new class to a previously defined class (without modifying the decla-
         ration for the old class).
These problems can be handled by defining a conversion operator for the source type. A member
          X: op er at or T(), where T is a type name, defines a conversion from X to T For exam-
function X :o pe ra to r T                                                               T.
                                                    Ti ny
ple, one could define a 6-bit non-negative integer, T in y, that can mix freely with integers in arith-
metic operations:
     cl as s Ti ny
     c la ss T in y {
              ch ar v;
             c ha r v
             v oi d a ss ig n(i nt i { i f (i 07 7) t hr ow B ad _r an ge ; v i; }
              vo id as si gn in t i) if i&~0 77 th ro w Ba d_ ra ng e() v=i
     pu bl ic
     p ub li c:
             c la ss B ad _r an ge { };
              cl as s Ba d_ ra ng e
           Ti ny in t i) as si gn i)
           T in y(i nt i { a ss ig n(i ; }
           Ti ny op er at or in t i) as si gn i) re tu rn th is
           T in y& o pe ra to r=(i nt i { a ss ig n(i ; r et ur n *t hi s; }
           op er at or in t() c on st { r et ur n v }
           o pe ra to r i nt  co ns t re tu rn v;         // conversion to int function
     };
                                         Ti ny                  in t                  in t
The range is checked whenever a T in y is initialized by an i nt and whenever an i nt is assigned to
                                                     Ti ny
one. No range check is needed when we copy a T in y, so the default copy constructor and assign-
ment are just right.
                                               Ti ny
     To enable the usual integer operations on T in y variables, we define the implicit conversion from
Ti ny in t, Ti ny op er at or in t(). Note that the type being converted to is part of the name of the
T in y to i nt T in y::o pe ra to r i nt
operator and cannot be repeated as the return value of the conversion function:
     Ti ny op er at or in t() c on st { r et ur n v }
     T in y::o pe ra to r i nt    co ns t re tu rn v;            // right
     in t Ti ny op er at or in t() c on st { r et ur n v }
     i nt T in y::o pe ra to r i nt   co ns t re tu rn v;        // error
In this respect also, a conversion operator resembles a constructor.
                  Ti ny                  in t                          in t
    Whenever a T in y appears where an i nt is needed, the appropriate i nt is used. For example:
     in t ma in
     i nt m ai n()
     {
           Ti ny c1 2;
           T in y c 1 = 2
           Ti ny c2 62
           T in y c 2 = 6 2;
           Ti ny c3 c2 c1
           T in y c 3 = c 2-c 1;      // c3 = 60
           Ti ny c4 c3
           T in y c 4 = c 3;          // no range check (not necessary)
           in t     c1 c2
           i nt i = c 1+c 2;          // i = 64
           c1 c1 c2
           c 1 = c 1+c 2;             // range error: c1 can’t be 64
               c3 64
           i = c 3-6 4;               // i = – 4
           c2 c3 64
           c 2 = c 3-6 4;             // range error: c2 can’t be – 4
           c3 c4
           c 3 = c 4;                 // no range check (not necessary)
     }




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
276     Operator Overloading                                                                Chapter 11



Conversion functions appear to be particularly useful for handling data structures when reading
(implemented by a conversion operator) is trivial, while assignment and initialization are distinctly
less trivial.
         is tr ea m    os tr ea m
    The i st re am and o st re am types rely on a conversion function to enable statements such as

       wh il e ci n>>x co ut x;
       w hi le (c in x) c ou t<<x

                       ci n>>x          is tr ea m&.
The input operation c in x returns an i st re am That value is implicitly converted to a value indi-
                    ci n.                                       wh il e
cating the state of c in This value can then be tested by the w hi le (see §21.3.3). However, it is typ-
ically not a good idea to define an implicit conversion from one type to another in such a way that
information is lost in the conversion.
    In general, it is wise to be sparing in the introduction of conversion operators. When used in
excess, they lead to ambiguities. Such ambiguities are caught by the compiler, but they can be a
nuisance to resolve. Probably the best idea is initially to do conversions by named functions, such
   X: ma ke _i nt
as X :m ak e_ in t(). If such a function becomes popular enough to make explicit use inelegant, it
                                            X: op er at or in t().
can be replaced by a conversion operator X :o pe ra to r i nt
    If both user-defined conversions and user-defined operators are defined, it is possible to get
ambiguities between the user-defined operators and the built-in operators. For example:

       in t op er at or Ti ny Ti ny
       i nt o pe ra to r+(T in y,T in y);
       vo id f(T in y t, in t i)
       v oi d f Ti ny t i nt i
       {
              t+i
              t i; // error, ambiguous: operator+(t,Tiny(i)) or int(t)+i ?
       }

It is therefore often best to rely on user-defined conversions or user-defined operators for a given
type, but not both.

11.4.1 Ambiguities [over.ambig]

An assignment of a value of type V to an object of class X is legal if there is an assignment operator
X: op er at or Z)                                                           Z.
X :o pe ra to r=(Z so that V is Z or there is a unique conversion of V to Z Initialization is treated
equivalently.
   In some cases, a value of the desired type can be constructed by repeated use of constructors or
conversion operators. This must be handled by explicit conversions; only one level of user-defined
implicit conversion is legal. In some cases, a value of the desired type can be constructed in more
than one way; such cases are illegal. For example:

       cl as s               X(i nt X(c ha r*)
       c la ss X { /* ... */ X in t); X ch ar ; };
       cl as s               Y(i nt
       c la ss Y { /* ... */ Y in t); };
       cl as s               Z(X
       c la ss Z { /* ... */ Z X); };
         f(X
       X f X);
         f(Y
       Y f Y);
         g(Z
       Z g Z);




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.4.1                                                                       Ambiguities      277


     vo id k1
     v oi d k 1()
     {
            f(1
            f 1);                 // error: ambiguous f(X(1)) or f(Y(1))?
            f(X 1))
            f X(1 ;               // ok
            f(Y 1))
            f Y(1 ;               // ok
           g("M ac k")
           g Ma ck ;       // error: two user-defined conversions needed; g(Z(X("Mack"))) not tried
           g(X Do c")); // ok: g(Z(X("Doc")))
           g X("D oc
           g(Z Su zy
           g Z("S uz y")); // ok: g(Z(X("Suzy")))
     }

User-defined conversions are considered only if they are necessary to resolve a call. For example:
     cl as s XX              XX in t)
     c la ss X X { /* ... */ X X(i nt ; };
     vo id h(d ou bl e)
     v oi d h do ub le ;
     vo id h(X X)
     v oi d h XX ;
     vo id k2
     v oi d k 2()
     {
            h(1
            h 1);        // h(double(1)) or h(XX(1))? h(double(1))!
     }

          h(1            h(d ou bl e(1
The call h 1) means h do ub le 1)) because that alternative uses only a standard conversion
rather than a user-defined conversion (§7.4).
    The rules for conversion are neither the simplest to implement, the simplest to document, nor
the most general that could be devised. They are, however, considerably safer, and the resulting
resolutions are less surprising. It is far easier to manually resolve an ambiguity than to find an error
caused by an unsuspected conversion.
    The insistence on strict bottom-up analysis implies that the return type is not used in overload-
ing resolution. For example:
     cl as s Qu ad
     c la ss Q ua d {
     pu bl ic
     p ub li c:
              Qu ad do ub le
             Q ua d(d ou bl e);
             // ...
     };
     Qu ad op er at or Qu ad Qu ad
     Q ua d o pe ra to r+(Q ua d,Q ua d);
     vo id f(d ou bl e a1 do ub le a2
     v oi d f do ub le a 1, d ou bl e a 2)
     {
            Qu ad r1 a1 a2
            Q ua d r 1 = a 1+a 2;          // double-precision add
            Qu ad r2 Qu ad a1 a2
            Q ua d r 2 = Q ua d(a 1)+a 2; // force quad arithmetic
     }

The reason for this design choice is partly that strict bottom-up analysis is more comprehensible
and partly that it is not considered the compiler’s job to decide which precision the programmer
might want for the addition.
    Once the types of both sides of an initialization or assignment have been determined, both types
are used to resolve the initialization or assignment. For example:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
278        Operator Overloading                                                             Chapter 11




       cl as s Re al
       c la ss R ea l {
       pu bl ic
       p ub li c:
                op er at or do ub le
               o pe ra to r d ou bl e();
                op er at or in t()
               o pe ra to r i nt ;
               // ...
       };
       vo id g(R ea l a)
       v oi d g Re al a
       {
              do ub le      a; // d = a.double();
              d ou bl e d = a
              in t
              i nt i = aa;     // i = a.int();
                a;
              d=a                  // d = a.double();
                a;
              i=a                  // i = a.int();
       }

In these cases, the type analysis is still bottom-up, with only a single operator and its argument
types considered at any one time.



11.5 Friends [over.friends]
An ordinary member function declaration specifies three logically distinct things:
    [1] The function can access the private part of the class declaration, and
    [2] the function is in the scope of the class, and
                                                               th is
    [3] the function must be invoked on an object (has a t hi s pointer).
                                      st at ic
By declaring a member function s ta ti c (§10.2.4), we can give it the first two properties only. By
                          fr ie nd
declaring a function a f ri en d, we can give it the first property only.
                                                                         Ma tr ix Ve ct or
    For example, we could define an operator that multiplies a M at ri x by a V ec to r. Naturally,
Ve ct or        Ma tr ix
V ec to r and M at ri x each hide their representation and provide a complete set of operations for
manipulating objects of their type. However, our multiplication routine cannot be a member of
both. Also, we don’t really want to provide low-level access functions to allow every user to both
                                                           Ma tr ix    Ve ct or
read and write the complete representation of both M at ri x and V ec to r. To avoid this, we declare
    op er at or
the o pe ra to r* a friend of both:

       cl as s Ma tr ix
       c la ss M at ri x;
       cl as s Ve ct or
       c la ss V ec to r {
               fl oa t v[4
               f lo at v 4];
               // ...
               fr ie nd Ve ct or op er at or co ns t Ma tr ix        co ns t Ve ct or
               f ri en d V ec to r o pe ra to r*(c on st M at ri x&, c on st V ec to r&);
       };
       cl as s Ma tr ix
       c la ss M at ri x {
               Ve ct or v[4
               V ec to r v 4];
               // ...
               fr ie nd Ve ct or op er at or co ns t Ma tr ix        co ns t Ve ct or
               f ri en d V ec to r o pe ra to r*(c on st M at ri x&, c on st V ec to r&);
       };




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.5                                                                                   Friends   279


     Ve ct or op er at or co ns t Ma tr ix m, co ns t Ve ct or v)
     V ec to r o pe ra to r*(c on st M at ri x& m c on st V ec to r& v
     {
             Ve ct or r;
             V ec to r r
             fo r in t         0; i<4 i++) {
             f or (i nt i = 0 i 4; i               // r[i] = m[i] * v;
                      r.v i] 0;
                      r v[i = 0
                      fo r in t      0; j<4 j++) r v[i += m v[i v[j * v v[j ;
                      f or (i nt j = 0 j 4; j     r.v i]        m.v i].v j] v.v j]
             }
             re tu rn r;
             r et ur n r
     }

  fr ie nd
A f ri en d declaration can be placed in either the private or the public part of a class declaration; it
does not matter where. Like a member function, a friend function is explicitly declared in the
declaration of the class of which it is a friend. It is therefore as much a part of that interface as is a
member function.
    A member function of one class can be the friend of another. For example:
     cl as s Li st _i te ra to r
     c la ss L is t_ it er at or {
             // ...
             in t* ne xt
             i nt n ex t();
     };
     cl as s Li st
     c la ss L is t {
             fr ie nd in t* Li st _i te ra to r: ne xt
             f ri en d i nt L is t_ it er at or :n ex t();
             // ...
     };

It is not unusual for all functions of one class to be friends of another. There is a shorthand for this:
     cl as s Li st
     c la ss L is t {
             fr ie nd cl as s Li st _i te ra to r;
             f ri en d c la ss L is t_ it er at or
             // ...
     };

                                        Li st _i te ra to r’s                        Li st
This friend declaration makes all of L is t_ it er at or member functions friends of L is t.
             fr ie nd
    Clearly, f ri en d classes should be used only to express closely connected concepts. Often, there
is a choice between making a class a member (a nested class) or a friend (§24.4).

11.5.1 Finding Friends [over.lookup]
                             fr ie nd
Like a member declaration, a f ri en d declaration does not introduce a name into an enclosing scope.
For example:
     cl as s Ma tr ix
     c la ss M at ri x {
             fr ie nd cl as s Xf or m;
             f ri en d c la ss X fo rm
             fr ie nd Ma tr ix in ve rt co ns t Ma tr ix
             f ri en d M at ri x i nv er t(c on st M at ri x&);
             // ...
     };
     Xf or m x;
     X fo rm x                                                // error: no Xform in scope
     Ma tr ix    p)(c on st Ma tr ix      in ve rt
     M at ri x (*p co ns t M at ri x&) = &i nv er t;          // error: no invert() in scope

For large programs and large classes, it is nice that a class doesn’t ‘‘quietly’’ add names to its




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
280     Operator Overloading                                                               Chapter 11



enclosing scope. For a template class that can be instantiated in many different contexts (Chapter
13), this is very important.
   A friend class must be previously declared in an enclosing scope or defined in the non-class
scope immediately enclosing the class that is declaring it a friend. For example:
       cl as s
       c la ss X { /* ... */ };              // Y’s friend
      na me sp ac e
      n am es pa ce N {
            cl as s
            c la ss Y {
                    fr ie nd cl as s X;
                    f ri en d c la ss X
                    fr ie nd cl as s Z;
                    f ri en d c la ss Z
                    fr ie nd cl as s AE
                    f ri en d c la ss A E;
            };
            cl as s
            c la ss Z { /* ... */ };         // Y’s friend
      }
      cl as s AE
      c la ss A E { /* ... */ };             // not a friend of Y

A friend function can be explicitly declared just like friend classes, or it can be found through its
argument types (§8.2.6) as if it was declared in the non-class scope immediately enclosing its class.
For example:
       vo id f(M at ri x& m)
       v oi d f Ma tr ix m
       {
              in ve rt m)
              i nv er t(m ;      // Matrix’s friend invert()
       }

It follows that a friend function should either be explicitly declared in an enclosing scope or take an
argument of its class. If not, the friend cannot be called. For example:
       // no f() here
       vo id g()
       v oi d g ;                            // X’s friend
       cl as s
       c la ss X {
               fr ie nd vo id f()
               f ri en d v oi d f ;           // useless
               fr ie nd vo id g()
               f ri en d v oi d g ;
               fr ie nd vo id h(c on st X&)
               f ri en d v oi d h co ns t X ; // can be found through its argument
       };
       vo id f() { /* ... */ }
       v oi d f                              // not a friend of X


11.5.2 Friends and Members [over.friends.members]
When should we use a friend function, and when is a member function the better choice for specify-
ing an operation? First, we try to minimize the number of functions that access the representation
of a class and try to make the set of access functions as appropriate as possible. Therefore, the first
question is not, ‘‘Should it be a member, a static member, or a friend?’’ but rather, ‘‘Does it really
need access?’’ Typically, the set of functions that need access is smaller than we are willing to
believe at first.
    Some operations must be members – for example, constructors, destructors, and virtual




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.5.2                                                          Friends and Members      281



functions (§12.2.6) – but typically there is a choice. Because member names are local to the class,
a function should be a member unless there is a specific reason for it to be a nonmember.
    Consider a class X presenting alternative ways of presenting an operation:
     cl as s
     c la ss X {
             // ...
             X(i nt
             X in t);
           in t m1
           i nt m 1();
           in t m2    co ns t;
           i nt m 2() c on st
           fr ie nd in t f1 X&)
           f ri en d i nt f 1(X ;
           fr ie nd in t f2 co ns t X&)
           f ri en d i nt f 2(c on st X ;
           fr ie nd in t f3 X)
           f ri en d i nt f 3(X ;
     };

Member functions can be invoked for objects of their class only; no user-defined conversions are
applied. For example:
     vo id g()
     v oi d g
     {
            99 m1
            9 9.m 1(); // error: X(99).m1() not tried
            99 m2
            9 9.m 2(); // error: X(99).m2() not tried
     }

                  X(i nt                                  99
The conversion X in t) is not applied to make an X out of 9 9.
                         f1
   The global function f 1() has a similar property because implicit conversions are not used for
    co ns t
non-c on st reference arguments (§5.5, §11.3.5). However, conversions may be applied to the argu-
          f2        f3
ments of f 2() and f 3():
     vo id h()
     v oi d h
     {
            f1 99
            f 1(9 9);   // error: f1(X(99)) not tried
            f2 99
            f 2(9 9);   // ok: f2(X(99));
            f3 99
            f 3(9 9);   // ok: f3(X(99));
     }

An operation modifying the state of a class object should therefore be a member or a global func-
                    co ns t                                co ns t
tion taking a non-c on st reference argument (or a non-c on st pointer argument). Operators that
require lvalue operands for the fundamental types (=, *=, ++, etc.) are most naturally defined as
members for user-defined types.
    Conversely, if implicit type conversion is desired for all operands of an operation, the function
                                                                co ns t
implementing it must be a nonmember function taking a c on st reference argument or a non-
reference argument. This is often the case for the functions implementing operators that do not
require lvalue operands when applied to fundamental types (+, -, ||, etc.). Such operators often
need access to the representations of their operand class. Consequently, binary operators are the
                           fr ie nd
most common source of f ri en d functions.
    If no type conversions are defined, there appears to be no compelling reason to choose a mem-
ber over a friend taking a reference argument, or vice versa. In some cases, the programmer may
have a preference for one call syntax over another. For example, most people seem to prefer the




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
282     Operator Overloading                                                                  Chapter 11



          in v(m                    Ma tr ix                        m.i nv
notation i nv m) for inverting a M at ri x m to the alternative m in v(). Naturally, if i nv in v() really
                                               Ma tr ix                         m,
does invert m itself, rather than return a new M at ri x that is the inverse of m it should be a member.
    All other things considered equal, choose a member. It is not possible to know if someone
someday will define a conversion operator. It is not always possible to predict if a future change
may require changes to the state of the object involved. The member function call syntax makes it
clear to the user that the object may be modified; a reference argument is far less obvious. Further-
more, expressions in the body of a member can be noticeably shorter than the equivalent expres-
sions in a global function; a nonmember function must use an explicit argument, whereas the mem-
              th is
ber can use t hi s implicitly. Also, because member names are local to the class they tend to be
shorter than the names of nonmember functions.


11.6 Large Objects [over.large]
                  co mp le x                                   co mp le x.
We defined the c om pl ex operators to take arguments of type c om pl ex This implies that for each
         co mp le x                                                                 do ub le s
use of a c om pl ex operator, each operand is copied. The overhead of copying two d ou bl es can be
noticeable but often less than what a pair of pointers impose. Unfortunately, not all classes have a
conveniently small representation. To avoid excessive copying, one can declare functions to take
reference arguments. For example:
       cl as s Ma tr ix
       c la ss M at ri x {
                do ub le m[4 4]
               d ou bl e m 4][4 ;
       pu bl ic
       p ub li c:
                Ma tr ix
               M at ri x();
                fr ie nd Ma tr ix op er at or co ns t Ma tr ix       co ns t Ma tr ix
               f ri en d M at ri x o pe ra to r+(c on st M at ri x&, c on st M at ri x&);
                fr ie nd Ma tr ix op er at or co ns t Ma tr ix       co ns t Ma tr ix
               f ri en d M at ri x o pe ra to r*(c on st M at ri x&, c on st M at ri x&);
       };

References allow the use of expressions involving the usual arithmetic operators for large objects
without excessive copying. Pointers cannot be used because it is not possible to redefine the mean-
ing of an operator applied to a pointer. Addition could be defined like this:
       Ma tr ix op er at or co ns t Ma tr ix ar g1 co ns t Ma tr ix ar g2
       M at ri x o pe ra to r+(c on st M at ri x& a rg 1, c on st M at ri x& a rg 2)
       {
               Ma tr ix su m;
               M at ri x s um
               fo r in t i=0 i<4 i++)
               f or (i nt i 0; i 4; i
                        fo r in t j=0 j<4 j++)
                        f or (i nt j 0; j 4; j
                                su m.m i][j      ar g1 m[i j] ar g2 m[i j]
                               s um m[i j] = a rg 1.m i][j + a rg 2.m i][j ;
               re tu rn su m;
               r et ur n s um
       }

     op er at or
This o pe ra to r+() accesses the operands of + through references but returns an object value.
Returning a reference would appear to be more efficient:
       cl as s Ma tr ix
       c la ss M at ri x {
               // ...
               fr ie nd Ma tr ix op er at or co ns t Ma tr ix         co ns t Ma tr ix
               f ri en d M at ri x& o pe ra to r+(c on st M at ri x&, c on st M at ri x&);
               fr ie nd Ma tr ix op er at or co ns t Ma tr ix         co ns t Ma tr ix
               f ri en d M at ri x& o pe ra to r*(c on st M at ri x&, c on st M at ri x&);
       };




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.6                                                                          Large Objects   283




This is legal, but it causes a memory allocation problem. Because a reference to the result will be
passed out of the function as a reference to the return value, the return value cannot be an automatic
variable (§7.3). Since an operator is often used more than once in an expression, the result cannot
      st at ic
be a s ta ti c local variable. The result would typically be allocated on the free store. Copying the
return value is often cheaper (in execution time, code space, and data space) than allocating and
(eventually) deallocating an object on the free store. It is also much simpler to program.
    There are techniques you can use to avoid copying the result. The simplest is to use a buffer of
static objects. For example:

     co ns t ma x_ ma tr ix _t em p 7;
     c on st m ax _m at ri x_ te mp = 7
     Ma tr ix ge t_ ma tr ix _t em p()
     M at ri x& g et _m at ri x_ te mp
     {
             st at ic in t nb uf 0;
             s ta ti c i nt n bu f = 0
             st at ic Ma tr ix bu f[m ax _m at ri x_ te mp
             s ta ti c M at ri x b uf ma x_ ma tr ix _t em p];
                           ma x_ ma tr ix _t em p) nb uf 0;
            i f (n bu f == m ax _m at ri x_ te mp n bu f = 0
            if nb uf
            re tu rn bu f[n bu f++];
            r et ur n b uf nb uf
     }
     Ma tr ix op er at or co ns t Ma tr ix ar g1 co ns t Ma tr ix ar g2
     M at ri x& o pe ra to r+(c on st M at ri x& a rg 1, c on st M at ri x& a rg 2)
     {
             Ma tr ix re s ge t_ ma tr ix _t em p()
             M at ri x& r es = g et _m at ri x_ te mp ;
             // ...
             re tu rn re s;
             r et ur n r es
     }


        Ma tr ix
Now a M at ri x is copied only when the result of an expression is assigned. However, heaven help
                                                          ma x_ ma tr ix _t em p
you if you write an expression that involves more than m ax _m at ri x_ te mp temporaries!
    A less error-prone technique involves defining the matrix type as a handle (§25.7) to a represen-
tation type that really holds the data. In that way, the matrix handles can manage the representation
objects in such a way that allocation and copying are minimized (see §11.12 and §11.14[18]).
However, that strategy relies on operators returning objects rather than references or pointers.
Another technique is to define ternary operations and have them automatically invoked for expres-
               a=b c       a+b i
sions such as a b+c and a b*i (§21.4.6.3, §22.4.7).



11.7 Essential Operators [over.essential]
                       X,                     X(c on st X&) takes care of initialization by an object
In general, for a type X the copy constructor X co ns t X
                    X.
of the same type X It cannot be overemphasized that assignment and initialization are different
operations (§10.4.4.1). This is especially important when a destructor is declared. If a class X has
a destructor that performs a nontrivial task, such as free-store deallocation, the class is likely to
need the full complement of functions that control construction, destruction, and copying:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
284     Operator Overloading                                                                        Chapter 11



       cl as s
       c la ss X {
               // ...
               X(S om et yp e)
               X So me ty pe ;               // constructor: create objects
               X(c on st X&)
               X co ns t X ;                 // copy constructor
               X& op er at or co ns t X&)
               X o pe ra to r=(c on st X ;   // copy assignment: cleanup and copy
                X()
               ~X ;                          // destructor: cleanup
       };
There are three more cases in which an object is copied: as a function argument, as a function
return value, and as an exception. When an argument is passed, a hitherto uninitialized variable –
the formal parameter – is initialized. The semantics are identical to those of other initializations.
The same is the case for function return values and exceptions, although that is less obvious. In
such cases, the copy constructor will be applied. For example:
       st ri ng g(s tr in g ar g)
       s tr in g g st ri ng a rg
       {
                re tu rn ar g;
                r et ur n a rg
       }
       in t ma in
       i nt m ai n ()
       {
             st ri ng       Ne wt on
             s tr in g s = "N ew to n";
                   g(s
             s = g s);
       }
                                        "N ew to n"
Clearly, the value of s ought to be " Ne wt on " after the call of g    g(). Getting a copy of the value of s
                       ar g                           st ri ng
into the argument a rg is not difficult; a call of s tr in g’s copy constructor does that. Getting a copy
of that value out of g                              st ri ng co ns t st ri ng
                        g() takes another call of s tr in g(c on st s tr in g&); this time, the variable initial-
                                                            s.
ized is a temporary one, which is then assigned to s Often one, but not both, of these copy opera-
tions can be optimized away. Such temporary variables are, of course, destroyed properly using
st ri ng     st ri ng
s tr in g::~s tr in g() (see §10.4.10).
                                                               X: op er at or co ns t X&) and the copy con-
      For a class X for which the assignment operator X :o pe ra to r=(c on st X
           X: X(c on st X&) are not explicitly declared by the programmer, the missing operation or
structor X :X co ns t X
operations will be generated by the compiler (§10.2.5).

11.7.1 Explicit Constructors [over.explicit]
By default, a single argument constructor also defines an implicit conversion. For some types, that
is ideal. For example:
       co mp le x     2;
       c om pl ex z = 2 // initialize z with complex(2)
In other cases, the implicit conversion is undesirable and error-prone. For example:
       st ri ng       a´; // make s a string with int(’a’) elements
       s tr in g s = ´a
It is quite unlikely that this was what the person defining s meant.
                                                                            ex pl ic it         ex pl ic it
     Implicit conversion can be suppressed by declaring a constructor e xp li ci t. That is, an e xp li ci t
constructor will be invoked only explicitly. In particular, where a copy constructor is in principle
                       ex pl ic it
needed (§11.3.4), an e xp li ci t constructor will not be implicitly invoked. For example:




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.7.1                                                                              Explicit Constructors   285



       cl as s St ri ng
       c la ss S tr in g {
               // ...
               ex pl ic it St ri ng in t n)
               e xp li ci t S tr in g(i nt n ;   // preallocate n bytes
               St ri ng co ns t ch ar p)
               S tr in g(c on st c ha r* p ;     // initial value is the C-style string p
       };
       S tr in g
       St ri ng    s 1 = ´a
                   s1      a´;                   // error: no implicit char– >String conversion
       St ri ng
       S tr in g   s2 10
                   s 2(1 0);                     // ok: String with space for 10 characters
       St ri ng
       S tr in g   s3 St ri ng 10
                   s 3 = S tr in g(1 0);         // ok: String with space for 10 characters
       St ri ng
       S tr in g   s4      Br ia n";
                   s 4 = "B ri an                // ok: s4 = String("Brian")
       St ri ng
       S tr in g   s5 Fa wl ty
                   s 5("F aw lt y");
       vo id f(S tr in g)
       v oi d f St ri ng ;
       St ri ng g()
       S tr in g g
       {
                f 10 ;
                f(1 0)                     // error: no implicit int– >String conversion
                f(S tr in g(1 0))
                f St ri ng 10 ;
                f("A rt hu r")
                f Ar th ur ;               // ok: f(String("Arthur"))
                f(s 1)
                f s1 ;
               St ri ng p1 ne w St ri ng Er ic
               S tr in g* p 1 = n ew S tr in g("E ri c");
               St ri ng p2 ne w St ri ng 10
               S tr in g* p 2 = n ew S tr in g(1 0);
               r et ur n 1 0;
               re tu rn 10                 // error: no implicit int– >String conversion
       }

The distinction between
       S tr in g s 1 = ´a
       St ri ng s1      a´;                // error: no implicit char– >String conversion

and
       St ri ng s2 10
       S tr in g s 2(1 0);                 // ok: string with space for 10 characters

may seem subtle, but it is less so in real code than in contrived examples.
      Da te                    in t                                  Da te
   In D at e, we used a plain i nt to represent a year (§10.3). Had D at e been critical in our design,
                              Ye ar
we might have introduced a Y ea r type to allow stronger compile-time checking. For example:
       cl as s Ye ar
       c la ss Y ea r {
                in t y;
               i nt y
       pu bl ic
       p ub li c:
                ex pl ic it Ye ar in t i) y(i
               e xp li ci t Y ea r(i nt i : y i) { }         // construct Year from int
                op er at or in t() c on st { r et ur n y }
               o pe ra to r i nt      co ns t re tu rn y;    // conversion: Year to int
       };
       cl as s Da te
       c la ss D at e {
       pu bl ic
       p ub li c:
                Da te in t d, Mo nt h m, Ye ar y)
               D at e(i nt d M on th m Y ea r y ;
               // ...
       };
       Da te d3 19 78 fe b,2 1)
       D at e d 3(1 97 8,f eb 21 ;       // error: 21 is not a Year
       Da te d4 21 fe b,Y ea r(1 97 8))
       D at e d 4(2 1,f eb Ye ar 19 78 ; // ok




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
286       Operator Overloading                                                                        Chapter 11



     Ye ar                                          in t.                 op er at or in t(), a Y ea r is
The Y ea r class is a simple ‘‘wrapper’’ around an i nt Thanks to the o pe ra to r i nt          Ye ar
                                in t                                                 ex pl ic it
implicitly converted into an i nt wherever needed. By declaring the constructor e xp li ci t, we make
              in t Ye ar
sure that the i nt to Y ea r happens only when we ask for it and that ‘‘accidental’’ assignments are
                                     Ye ar
caught at compile time. Because Y ea r’s member functions are easily inlined, no run-time or space
costs are added.
   A similar technique can be used to define range types (§25.6.1).



11.8 Subscripting [over.subscript]
    op er at or
An o pe ra to r[] function can be used to give subscripts a meaning for class objects. The second
                                   op er at or
argument (the subscript) of an o pe ra to r[] function may be of any type. This makes it possible to
       ve ct or
define v ec to rs, associative arrays, etc.
    As an example, let us recode the example from §5.5 in which an associative array is used to
write a small program for counting the number of occurrences of words in a file. There, a function
is used. Here, an associative array type is defined:

       cl as s As so c
       c la ss A ss oc {
               st ru ct Pa ir
               s tr uc t P ai r {
                        st ri ng na me
                        s tr in g n am e;
                        do ub le va l;
                        d ou bl e v al
                        Pa ir st ri ng          do ub le     0) na me n) va l(v
                        P ai r(s tr in g n ="", d ou bl e v =0 :n am e(n , v al v) { }
               };
               ve ct or Pa ir ve c;
               v ec to r<P ai r> v ec
               As so c(c on st As so c&)
              A ss oc co ns t A ss oc ;                      // private to prevent copying
               As so c& op er at or co ns t As so c&)
              A ss oc o pe ra to r=(c on st A ss oc ;        // private to prevent copying
      pu bl ic
      p ub li c:
               As so c() {}
              A ss oc
               do ub le op er at or      co ns t st ri ng
              d ou bl e& o pe ra to r[](c on st s tr in g&);
              v oi d p ri nt _a ll c on st
               vo id pr in t_ al l() co ns t;
      };

   As so c                   Pa ir
An A ss oc keeps a vector of P ai rs. The implementation uses the same trivial and inefficient search
method as in §5.5:

       do ub le As so c: op er at or        co ns t st ri ng s)
       d ou bl e& A ss oc :o pe ra to r[](c on st s tr in g& s
               // search for s; return its value if found; otherwise, make a new Pair and return the default value 0
       {
               f or (v ec to r<P ai r>::c on st _i te ra to r p = v ec be gi n(); p ve c.e nd ; ++p
               fo r ve ct or Pa ir      co ns t_ it er at or      ve c.b eg in    p!=v ec en d()  p)
                      if s       p->n am e) re tu rn p->v al
                      i f (s == p na me r et ur n p va l;
             v ec pu sh _b ac k(P ai r(s 0));
             ve c.p us h_ ba ck Pa ir s,0          // initial value: 0
             re tu rn ve c.b ac k().v al
             r et ur n v ec ba ck   va l;          // return last element (§16.3.3)
      }

                                 As so c
Because the representation of an A ss oc is hidden, we need a way of printing it:




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.8                                                                                Subscripting   287




     v oi d A ss oc :p ri nt _a ll   co ns t
     vo id As so c: pr in t_ al l() c on st
     {
            f or (v ec to r<P ai r>::c on st _i te ra to r p = v ec be gi n(); p ve c.e nd ; ++p
            fo r ve ct or Pa ir      co ns t_ it er at or      ve c.b eg in    p!=v ec en d()  p)
                   co ut      p->n am e                    p->v al
                   c ou t << p na me << ": " << p va l << ´\ n´;          \n
     }

Finally, we can write the trivial main program:

     in t ma in
     i nt m ai n()        // count the occurrences of each word on input
     {
            st ri ng bu f;
           s tr in g b uf
           As so c ve c;
           A ss oc v ec
           wh il e ci n>>b uf ve c[b uf
           w hi le (c in bu f) v ec bu f]++;
           ve c.p ri nt _a ll
           v ec pr in t_ al l();
     }

A further development of the idea of an associative array can be found in §17.4.1.
       op er at or
   An o pe ra to r[]() must be a member function.



11.9 Function Call [over.call]
Function call, that is, the notation expression(expression-list), can be interpreted as a binary opera-
tion with the expression as the left-hand operand and the expression-list as the right-hand operand.
The call operator () can be overloaded in the same way as other operators can. An argument list
        op er at or
for an o pe ra to r()() is evaluated and checked according to the usual argument-passing rules.
Overloading function call seems to be useful primarily for defining types that have only a single
operation and for types for which one operation is predominant.
    The most obvious, and probably also the most important, use of the () operator is to provide
the usual function call syntax for objects that in some way behave like functions. An object that
acts like a function is often called a function-like object or simply a function object (§18.4). Such
function objects are important because they allow us to write code that takes nontrivial operations
as parameters. For example, the standard library provides many algorithms that invoke a function
for each element of a container. Consider:

     vo id ne ga te co mp le x& c)        c;
     v oi d n eg at e(c om pl ex c { c = -c }
     vo id f(v ec to r<c om pl ex    aa li st co mp le x>& l l)
     v oi d f ve ct or co mp le x>& a a, l is t<c om pl ex ll
     {
            f or _e ac h(a a.b eg in ,a a.e nd ,n eg at e); // negate all vector elements
            fo r_ ea ch aa be gi n() aa en d() ne ga te
            f or _e ac h(l l.b eg in ,l l.e nd ,n eg at e); // negate all list elements
            fo r_ ea ch ll be gi n() ll en d() ne ga te
     }

This negates every element in the vector and the list.
                             co mp le x(2 3)
   What if we wanted to add c om pl ex 2,3 to every element? That is easily done like this:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
288     Operator Overloading                                                                                Chapter 11



       vo id ad d2 3(c om pl ex c)
       v oi d a dd 23 co mp le x& c
       {
                    co mp le x(2 3)
              c += c om pl ex 2,3 ;
       }
      vo id g(v ec to r<c om pl ex     aa li st co mp le x>& l l)
      v oi d g ve ct or co mp le x>& a a, l is t<c om pl ex  ll
      {
             f or _e ac h(a a.b eg in ,a a.e nd ,a dd 23 ;
             fo r_ ea ch aa be gi n() aa en d() ad d2 3)
             f or _e ac h(l l.b eg in ,l l.e nd ,a dd 23 ;
             fo r_ ea ch ll be gi n() ll en d() ad d2 3)
      }

How would we write a function to repeatedly add an arbitrary complex value? We need something
to which we can pass that arbitrary value and which can then use that value each time it is called.
That does not come naturally for functions. Typically, we end up ‘‘passing’’ the arbitrary value by
leaving it in the function’s surrounding context. That’s messy. However, we can write a class that
behaves in the desired way:
       cl as s Ad d
       c la ss A dd {
                co mp le x va l;
               c om pl ex v al
       pu bl ic
       p ub li c:
                Ad d(c om pl ex c) va l c;
               A dd co mp le x c { v al = c }                                    // save value
                Ad d(d ou bl e r, do ub le i) va l co mp le x(r i)
               A dd do ub le r d ou bl e i { v al = c om pl ex r,i ; }
             vo id op er at or     co mp le x& c) co ns t      va l;
             v oi d o pe ra to r()(c om pl ex c c on st { c += v al }            // add value to argument
       };

                    Ad d
An object of class A dd is initialized with a complex number, and when invoked using (), it adds
that number to its argument. For example:
      vo id h(v ec to r<c om pl ex     aa li st co mp le x>& l l, c om pl ex z
      v oi d h ve ct or co mp le x>& a a, l is t<c om pl ex  ll co mp le x z)
      {
             f or _e ac h(a a.b eg in ,a a.e nd ,A dd 2,3 ;
             fo r_ ea ch aa be gi n() aa en d() Ad d(2 3))
             f or _e ac h(l l.b eg in ,l l.e nd ,A dd z));
             fo r_ ea ch ll be gi n() ll en d() Ad d(z
      }

               co mp le x(2 3)
This will add c om pl ex 2,3 to every element of the array and z to every element on the list. Note
that A dd z) constructs an object that is used repeatedly by f or _e ac h(). It is not simply a function
      Ad d(z                                                    fo r_ ea ch
                                                                                              Ad d(z
that is called once or even called repeatedly. The function that is called repeatedly is A dd z)’s
op er at or
o pe ra to r()().
    This all works because f or _e ac h is a template that applies () to its third argument without car-
                            fo r_ ea ch
ing exactly what that third argument really is:
       t em pl at e<c la ss I te r, c la ss F ct I te r f or _e ac h(I te r b I te r e F ct f
       te mp la te cl as s It er cl as s Fc t> It er fo r_ ea ch It er b, It er e, Fc t f)
       {
               wh il e b        e) f(*b
               w hi le (b != e f b++);
               re tu rn b;
               r et ur n b
       }

At first glance, this technique may look esoteric, but it is simple, efficient, and extremely useful
(see §3.8.5, §18.4).




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.9                                                                                    Function Call   289



                          op er at or
    Other popular uses of o pe ra to r()() are as a substring operator and as a subscripting operator
for multidimensional arrays (§22.4.5).
       op er at or
    An o pe ra to r()() must be a member function.


11.10 Dereferencing [over.deref]
The dereferencing operator -> can be defined as a unary postfix operator. That is, given a class
     cl as s Pt r
     c la ss P tr {
             // ...
             X* op er at or
             X o pe ra to r->();
     };

                 Pt r
objects of class P tr can be used to access members of class X in a very similar manner to the way
pointers are used. For example:
     vo id f(P tr p)
     v oi d f Pt r p
     {
            p m=7
            p->m 7;                // (p.operator– >())– >m = 7
     }

                                                     p.o pe ra to r->() does not depend on the mem-
The transformation of the object p into the pointer p op er at or
                                              op er at or
ber m pointed to. That is the sense in which o pe ra to r->() is a unary postfix operator. However,
there is no new syntax introduced, so a member name is still required after the ->. For example:
     vo id g(P tr p)
     v oi d g Pt r p
     {
            X* q1 p->;
            X q1 = p                  // syntax error
            X* q2 p.o pe ra to r->(); // ok
            X q 2 = p op er at or
     }

Overloading -> is primarily useful for creating ‘‘smart pointers,’’ that is, objects that act like point-
ers and in addition perform some action whenever an object is accessed through them. For exam-
ple, one could define a class R ec _p tr for accessing objects of class R ec stored on disk. R ec _p tr
                              Re c_ pt r                                Re c                       Re c_ pt r’s
constructor takes a name that can be used to find the object on disk, R ec _p tr :o pe ra to r->()
                                                                                Re c_ pt r: op er at or
brings the object into main memory when accessed through its R ec _p tr and R ec _p tr destructor
                                                                    Re c_ pt r,       Re c_ pt r’s
eventually writes the updated object back out to disk:
     c la ss R ec _p tr {
     cl as s Re c_ pt r
             Re c* in _c or e_ ad dr es s;
             R ec i n_ co re _a dd re ss
             co ns t ch ar id en ti fi er
             c on st c ha r* i de nt if ie r;
             // ...
     pu bl ic
     p ub li c:
              Re c_ pt r(c on st ch ar p) id en ti fi er p) in _c or e_ ad dr es s(0
             R ec _p tr co ns t c ha r* p : i de nt if ie r(p , i n_ co re _a dd re ss 0) { }
               Re c_ pt r() { w ri te _t o_ di sk in _c or e_ ad dr es s,i de nt if ie r); }
             ~R ec _p tr        wr it e_ to _d is k(i n_ co re _a dd re ss id en ti fi er
              Re c* op er at or
             R ec o pe ra to r->();
     };




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
290        Operator Overloading                                                                                 Chapter 11


      R ec R ec _p tr :o pe ra to r->()
      Re c* Re c_ pt r: op er at or
      {
            if in _c or e_ ad dr es s        0) in _c or e_ ad dr es s re ad _f ro m_ di sk id en ti fi er
            i f (i n_ co re _a dd re ss == 0 i n_ co re _a dd re ss = r ea d_ fr om _d is k(i de nt if ie r);
            re tu rn in _c or e_ ad dr es s;
            r et ur n i n_ co re _a dd re ss
      }
R ec _p tr might be used like this:
Re c_ pt r
       st ru ct Re c
       s tr uc t R ec {       // the Rec that a Rec_ptr points to
                st ri ng na me
                s tr in g n am e;
                // ...
       };
       vo id up da te co ns t ch ar s)
       v oi d u pd at e(c on st c ha r* s
       {
              R ec _p tr p s);
              Re c_ pt r p(s                     // get Rec_ptr for s

              p->n am e  Ro sc oe
              p na me = "R os co e";             // update s; if necessary, first retrieve from disk
              // ...
       }
Naturally, a real R ec _p tr would be a template so that the R ec type is a parameter. Also, a realistic
                  Re c_ pt r                                 Re c
program would contain error-handling code and use a less naive way of interacting with the disk.
   For ordinary pointers, use of -> is synonymous with some uses of unary * and []. Given
       Y* p;
       Y p
it holds that
       p->m     p).m   p[0 m
       p m == (*p m == p 0].m
As usual, no such guarantee is provided for user-defined operators. The equivalence can be pro-
vided where desired:
      cl as s Pt r_ to _Y
      c la ss P tr _t o_ Y {
               Y* p;
              Y p
      pu bl ic
      p ub li c:
               Y* op er at or       re tu rn p;
              Y o pe ra to r->() { r et ur n p }
               Y& op er at or      re tu rn p;
              Y o pe ra to r*() { r et ur n *p }
               Y& op er at or  in t i) re tu rn p[i
              Y o pe ra to r[](i nt i { r et ur n p i]; }
      };
If you provide more than one of these operators, it might be wise to provide the equivalence, just as
                              x     x+=1                           x=x 1
it is wise to ensure that ++x and x 1 have the same effect as x x+1 for a simple variable x of
some class if ++, +=, =, and + are provided.
     The overloading of -> is important to a class of interesting programs and not just a minor
curiosity. The reason is that indirection is a key concept and that overloading -> provides a clean,
direct, and efficient way of representing indirection in a program. Iterators (Chapter 19) provide an
important example of this. Another way of looking at operator -> is to consider it as a way of pro-
viding C++ with a limited, but useful, form of delegation (§24.2.4).
     Operator -> must be a member function. If used, its return type must be a pointer or an object
                                                                                   op er at or
of a class to which you can apply ->. When declared for a template class, o pe ra to r->() is




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.10                                                                    Dereferencing    291



frequently unused, so it makes sense to postpone checking the constraint on the return type until
actual use.



11.11 Increment and Decrement [over.incr]
Once people invent ‘‘smart pointers,’’ they often decide to provide the increment operator ++ and
the decrement operator -- to mirror these operators’ use for built-in types. This is especially obvi-
ous and necessary where the aim is to replace an ordinary pointer type with a ‘‘smart pointer’’ type
that has the same semantics, except that it adds a bit of run-time error checking. For example, con-
sider a troublesome traditional program:

     vo id f1 T a)
     v oi d f 1(T a        // traditional use
     {
                v[2 00
            T v 20 0];
            T*         v[0
            T p = &v 0];
            p--;
            p
               p a; // Oops: ‘p’ out of range, uncaught
            *p = a
            ++p p;
               p a; // ok
            *p = a
     }


                                                                 Pt r_ to _T
We might want to replace the pointer p with an object of a class P tr _t o_ T that can be dereferenced
only provided it actually points to an object. We would also like to ensure that p can be incre-
mented and decremented, only provided it points to an object within an array and the increment and
decrement operations yield an object within the array. That is we would like something like this:

     cl as s Pt r_ to _T
     c la ss P tr _t o_ T {
             // ...
     };
     vo id f2 T a)
     v oi d f 2(T a          // checked
     {
                v[2 00
            T v 20 0];
            Pt r_ to _T p(&v 0] v,2 00
            P tr _t o_ T p v[0 ,v 20 0);
            p--;
            p
               p a; // run-time error: ‘p’ out of range
            *p = a
            ++p p;
               p a; // ok
            *p = a
     }


The increment and decrement operators are unique among C++ operators in that they can be used as
both prefix and postfix operators. Consequently, we must define prefix and postfix increment and
           Pt r_ to _T
decrement P tr _t o_ T. For example:




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
292     Operator Overloading                                                                         Chapter 11



       cl as s Pt r_ to _T
       c la ss P tr _t o_ T {
                T* p;
               T p
                T* ar ra y;
               T a rr ay
                in t si ze
               i nt s iz e;
       pu bl ic
       p ub li c:
              Pt r_ to _T T* p, T* v, in t s)
              P tr _t o_ T(T p T v i nt s ;          // bind to array v of size s, initial value p
              Pt r_ to _T T* p)
              P tr _t o_ T(T p ;                     // bind to single object, initial value p
              Pt r_ to _T op er at or
              P tr _t o_ T& o pe ra to r++();        // prefix
              Pt r_ to _T op er at or
              P tr _t o_ T o pe ra to r++(i nt ;
                                          in t)      // postfix
              Pt r_ to _T op er at or
              P tr _t o_ T& o pe ra to r--();        // prefix
              Pt r_ to _T op er at or
              P tr _t o_ T o pe ra to r--(i nt ;
                                          in t)      // postfix
              T& op er at or
              T o pe ra to r*();         // prefix
      };
     in t
The i nt argument is used to indicate that the function is to be invoked for postfix application of ++.
      in t
This i nt is never used; the argument is simply a dummy used to distinguish between prefix and
                                                                   op er at or
postfix application. The way to remember which version of an o pe ra to r++ is prefix is to note that
the version without the dummy argument is prefix, exactly like all the other unary arithmetic and
logical operators. The dummy argument is used only for the ‘‘odd’’ postfix ++ and --.
           Pt r_ to _T
    Using P tr _t o_ T, the example is equivalent to:
      vo id f3 T a)
      v oi d f 3(T a            // checked
      {
                 v[2 00
             T v 20 0];
             Pt r_ to _T p(&v 0] v,2 00
             P tr _t o_ T p v[0 ,v 20 0);
             p.o pe ra to r--(0 ;
             p op er at or    0)
             p.o pe ra to r*() = a // run-time error: ‘p’ out of range
             p op er at or       a;
             p.o pe ra to r++();
             p op er at or
             p.o pe ra to r*() = a // ok
             p op er at or       a;
      }
                   Pt r_ to _T
Completing class P tr _t o_ T is left as an exercise (§11.14[19]). Its elaboration into a template using
exceptions to report the run-time errors is another exercise (§14.12[2]). An example of operators
++ and -- for iteration can be found in §19.3. A pointer template that behaves correctly with
respect to inheritance is presented in (§13.6.3).


11.12 A String Class [over.string]
                                          St ri ng
Here is a more realistic version of class S tr in g. I designed it as the minimal string that served my
needs. This string provides value semantics, character read and write operations, checked and
unchecked access, stream I/O, literal strings as literals, and equality and concatenation operators. It
represents strings as C-style, zero-terminated arrays of characters and uses reference counts to mini-
mize copying. Writing a better string class and/or one that provides more facilities is a good exer-
cise (§11.14[7-12]). That done, we can throw away our exercises and use the standard library
string (Chapter 20).




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.12                                                                    A String Class    293



                      St ri ng                                Sr ep
    My almost-real S tr in g employs three auxiliary classes: S re p, to allow an actual representation
                               St ri ng                        Ra ng e,
to be shared between several S tr in gs with the same value; R an ge to be thrown in case of range
            Cr ef
errors, and C re f, to help implement a subscript operator that distinguishes between reading and
writing:

     cl as s St ri ng
     c la ss S tr in g {
              st ru ct Sr ep
             s tr uc t S re p;              // representation
              Sr ep re p;
             S re p *r ep
     pu bl ic
     p ub li c:
              cl as s Cr ef
             c la ss C re f;                // reference to char
            cl as s Ra ng e
            c la ss R an ge { };            // for exceptions
            // ...
     };


Like other members, a member class (often called a nested class) can be declared in the class itself
and defined later:

     st ru ct St ri ng Sr ep
     s tr uc t S tr in g::S re p {
              ch ar s;
              c ha r* s            // pointer to elements
              in t sz
              i nt s z;            // number of characters
              in t n;
              i nt n               // reference count
            Sr ep in t ns z, co ns t ch ar p)
            S re p(i nt n sz c on st c ha r* p
            {
                   n=1   1;
                   sz ns z;
                   s z = n sz
                         ne w ch ar sz 1]
                   s = n ew c ha r[s z+1 ; // add space for terminator
                   st rc py s,p
                   s tr cp y(s p);
            }
             Sr ep      de le te    s;
            ~S re p() { d el et e[] s }
            S re p* g et _o wn _c op y()
            Sr ep ge t_ ow n_ co py           // clone if necessary
            {
                   if n==1 re tu rn th is
                   i f (n 1) r et ur n t hi s;
                   n--;
                   n
                   re tu rn ne w Sr ep sz s)
                   r et ur n n ew S re p(s z,s ;
            }
            vo id as si gn in t ns z, co ns t ch ar p)
            v oi d a ss ig n(i nt n sz c on st c ha r* p
            {
                   if sz          ns z)
                   i f (s z != n sz {
                            de le te    s;
                            d el et e[] s
                            sz ns z;
                            s z = n sz
                                  ne w ch ar sz 1]
                            s = n ew c ha r[s z+1 ;
                   }
                   st rc py s,p
                   s tr cp y(s p);
            }




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
294     Operator Overloading                                                                 Chapter 11


       pr iv at e:
       p ri va te                           // prevent copying:
                Sr ep co ns t Sr ep
                S re p(c on st S re p&);
                Sr ep op er at or co ns t Sr ep
                S re p& o pe ra to r=(c on st S re p&);
       };

      St ri ng
Class S tr in g provides the usual set of constructors, destructor, and assignment operations:
       cl as s St ri ng
       c la ss S tr in g {
               // ...
              St ri ng
              S tr in g();                        // x = ""
              St ri ng co ns t ch ar
              S tr in g(c on st c ha r*);         // x = "abc"
              St ri ng co ns t St ri ng
              S tr in g(c on st S tr in g&);      // x = other_string
              St ri ng op er at or co ns t ch ar
              S tr in g& o pe ra to r=(c on st c ha r *);
              St ri ng op er at or co ns t St ri ng
              S tr in g& o pe ra to r=(c on st S tr in g&);
                St ri ng
              ~S tr in g();
              // ...
      };

      St ri ng                                                   s1 s2                     s1       s2
This S tr in g has value semantics. That is, after an assignment s 1=s 2, the two strings s 1 and s 2 are
fully distinct and subsequent changes to the one have no effect on the other. The alternative would
             St ri ng                                                     s2      s1 s2
be to give S tr in g pointer semantics. That would be to let changes to s 2 after s 1=s 2 also affect the
            s1
value of s 1. For types with conventional arithmetic operations, such as complex, vector, matrix,
                                                                                                St ri ng
and string, I prefer value semantics. However, for the value semantics to be affordable, a S tr in g is
implemented as a handle to its representation and the representation is copied only when necessary:
       St ri ng St ri ng
       S tr in g::S tr in g()        // the empty string is the default value
       {
                re p ne w Sr ep 0,"");
                r ep = n ew S re p(0
       }
      St ri ng St ri ng co ns t St ri ng x)
      S tr in g::S tr in g(c on st S tr in g& x // copy constructor
      {
               x.r ep n++;
               x re p->n
               re p x.r ep
               r ep = x re p;      // share representation
      }
      St ri ng       St ri ng
      S tr in g::~S tr in g()
      {
               if       re p->n 0) de le te re p;
               i f (--r ep n == 0 d el et e r ep
      }
      St ri ng St ri ng op er at or co ns t St ri ng x)
      S tr in g& S tr in g::o pe ra to r=(c on st S tr in g& x        // copy assignment
      {
               x.r ep n++;
               x re p->n                                  // protects against ‘‘st = st’’
               if       re p->n      0) de le te re p;
               i f (--r ep n == 0 d el et e r ep
               re p x.r ep
               r ep = x re p;                             // share representation
               re tu rn th is
               r et ur n *t hi s;
      }

                              co ns t ch ar
Pseudo-copy operations taking c on st c ha r* arguments are provided to allow string literals:




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.12                                                                            A String Class   295



     St ri ng St ri ng co ns t ch ar s)
     S tr in g::S tr in g(c on st c ha r* s
     {
              re p ne w Sr ep st rl en s) s)
              r ep = n ew S re p(s tr le n(s ,s ;
     }
     St ri ng St ri ng op er at or co ns t ch ar s)
     S tr in g& S tr in g::o pe ra to r=(c on st c ha r* s
     {
              if re p->n
              i f (r ep n == 1    1)                    // recycle Srep
                       re p->a ss ig n(s tr le n(s s)
                       r ep as si gn st rl en s),s ;
              el se
              e ls e {                                  // use new Srep
                       re p->n
                       r ep n--;
                       re p ne w Sr ep st rl en s) s)
                       r ep = n ew S re p(s tr le n(s ,s ;
              }
              re tu rn th is
              r et ur n *t hi s;
     }
The design of access operators for a string is a difficult topic because ideally access is by conven-
tional notation (that is, using []), maximally efficient, and range checked. Unfortunately, you can-
not have all of these properties simultaneously. My choice here has been to provide efficient
unchecked operations with a slightly inconvenient notation plus slightly less efficient checked oper-
ators with the conventional notation:
     cl as s St ri ng
     c la ss S tr in g {
             // ...
            vo id ch ec k(i nt i) co ns t if i<0        re p->s z<=i th ro w Ra ng e()
            v oi d c he ck in t i c on st { i f (i 0 || r ep sz i) t hr ow R an ge ; }
            ch ar re ad in t i) co ns t re tu rn re p->s i]
            c ha r r ea d(i nt i c on st { r et ur n r ep s[i ; }
            v oi d w ri te in t i c ha r c { r ep re p->g et _o wn _c op y(); r ep s[i c; }
            vo id wr it e(i nt i, ch ar c) re p=r ep ge t_ ow n_ co py        re p->s i]=c
            Cr ef op er at or     in t i) ch ec k(i re tu rn Cr ef th is i)
            C re f o pe ra to r[](i nt i { c he ck i); r et ur n C re f(*t hi s,i ; }
            ch ar op er at or     in t i) co ns t ch ec k(i re tu rn re p->s i]
            c ha r o pe ra to r[](i nt i c on st { c he ck i); r et ur n r ep s[i ; }
            in t si ze    co ns t re tu rn re p->s z;
            i nt s iz e() c on st { r et ur n r ep sz }
            // ...
     };
The idea is to use [] to get checked access for ordinary use, but to allow the user to optimize by
checking the range once for a set of accesses. For example:
     in t ha sh co ns t St ri ng s)
     i nt h as h(c on st S tr in g& s
     {
            in t       s.r ea d(0
            i nt h = s re ad 0);
            co ns t in t ma x s.s iz e()
            c on st i nt m ax = s si ze ;
            fo r in t       1; i<m ax i++) h ^= s re ad i)>>1 // unchecked access to s
            f or (i nt i = 1 i ma x; i          s.r ea d(i  1;
            re tu rn h;
            r et ur n h
     }
Defining an operator, such as [], to be used for both reading and writing is difficult where it is not
acceptable simply to return a reference and let the user decide what to do with it. Here, that is not a
                                                  St ri ng
reasonable alternative because I have defined S tr in g so that the representation is shared between
St ri ng
S tr in gs that have been assigned, passed as value arguments, etc., until someone actually writes to a




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
296        Operator Overloading                                                                Chapter 11



St ri ng
S tr in g. Then, and only then, is the representation copied. This technique is usually called copy-
on-write. The actual copy is done by S tr in g::S re p::g et _o wn _c op y().
                                            St ri ng Sr ep ge t_ ow n_ co py
      To get these access functions inlined, their definitions must be placed so that the definition of
Sr ep                                               Sr ep                      St ri ng
S re p is in scope. This implies that either S re p is defined within S tr in g or the access functions are
           in li ne         St ri ng          St ri ng Sr ep
defined i nl in e outside S tr in g and after S tr in g::S re p (§11.14[2]).
                                                          St ri ng op er at or           Cr ef
      To distinguish between a read and a write, S tr in g::o pe ra to r[]() returns a C re f when called
                    co ns t                 Cr ef                             ch ar
for a non-c on st object. A C re f behaves like a c ha r&, except that it calls
S tr in g::S re p::g et _o wn _c op y() when written to:
St ri ng Sr ep ge t_ ow n_ co py

       cl as s St ri ng Cr ef
       c la ss S tr in g::C re f {            // reference to s[i]
       fr ie nd cl as s St ri ng
       f ri en d c la ss S tr in g;
                St ri ng s;
                S tr in g& s
                in t i;
                i nt i
                Cr ef St ri ng ss in t ii          s(s s) i(i i)
                C re f(S tr in g& s s, i nt i i) : s ss , i ii { }
       pu bl ic
       p ub li c:
                op er at or ch ar         re tu rn s.r ea d(i
                o pe ra to r c ha r() { r et ur n s re ad i); }            // yield value
                vo id op er at or ch ar c) s.w ri te i,c
                v oi d o pe ra to r=(c ha r c { s wr it e(i c); }          // change value
       };

For example:

       vo id f(S tr in g s, co ns t St ri ng r)
       v oi d f St ri ng s c on st S tr in g& r
       {
              in t c1 s[1
              i nt c 1 = s 1]; // c1 = s.operator[](1).operator char()
              s[1
              s 1] = ´c  c´;     // s.operator[](1).operator=(’c’)
              in t c2 r[1
              i nt c 2 = r 1]; // c2 = r.operator[](1)
              r[1
              r 1] = ´d  d´;   // error: assignment to char, r.operator[](1) = ’d’
       }

                    co ns t        s.o pe ra to r[](1 is C re f(s 1).
Note that for a non-c on st object s op er at or    1) Cr ef s,1
                       St ri ng
   To complete class S tr in g, I provide a set of useful functions:

       cl as s St ri ng
       c la ss S tr in g {
               // ...
              St ri ng op er at or      co ns t St ri ng
              S tr in g& o pe ra to r+=(c on st S tr in g&);
              St ri ng op er at or      co ns t ch ar
              S tr in g& o pe ra to r+=(c on st c ha r*);
              fr ie nd os tr ea m& op er at or     os tr ea m&, c on st S tr in g&);
              f ri en d o st re am o pe ra to r<<(o st re am    co ns t St ri ng
              fr ie nd is tr ea m& op er at or    is tr ea m&, S tr in g&);
              f ri en d i st re am o pe ra to r>>(i st re am   St ri ng
              fr ie nd bo ol op er at or       co ns t St ri ng x, co ns t ch ar s)
              f ri en d b oo l o pe ra to r==(c on st S tr in g& x c on st c ha r* s
                         re tu rn st rc mp x.r ep s, s)
                       { r et ur n s tr cm p(x re p->s s == 0 }   0;
              fr ie nd bo ol op er at or       co ns t St ri ng x, co ns t St ri ng y)
              f ri en d b oo l o pe ra to r==(c on st S tr in g& x c on st S tr in g& y
                         re tu rn st rc mp x.r ep s, y.r ep s)
                       { r et ur n s tr cm p(x re p->s y re p->s == 0 }    0;
              fr ie nd bo ol op er at or       co ns t St ri ng x, co ns t ch ar s)
              f ri en d b oo l o pe ra to r!=(c on st S tr in g& x c on st c ha r* s
                         re tu rn st rc mp x.r ep s, s)
                       { r et ur n s tr cm p(x re p->s s != 0 }   0;




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.12                                                                             A String Class   297


              fr ie nd bo ol op er at or       co ns t St ri ng x, co ns t St ri ng y)
              f ri en d b oo l o pe ra to r!=(c on st S tr in g& x c on st S tr in g& y
                         re tu rn st rc mp x.r ep s, y.r ep s)
                       { r et ur n s tr cm p(x re p->s y re p->s != 0 }    0;
       };
       St ri ng op er at or co ns t St ri ng       co ns t St ri ng
       S tr in g o pe ra to r+(c on st S tr in g&, c on st S tr in g&);
       St ri ng op er at or co ns t St ri ng       co ns t ch ar
       S tr in g o pe ra to r+(c on st S tr in g&, c on st c ha r*);
To save space, I have left the I/O and concatenation operations as exercises.
                                            St ri ng
   The main program simply exercises the S tr in g operators a bit:
        St ri ng f(S tr in g a, St ri ng b)
        S tr in g f St ri ng a S tr in g b
        {
                 a[2
                 a 2] = ´x   x´;
                 ch ar       b[3
                 c ha r c = b 3];
                 co ut       in f:                                   \n
                 c ou t << "i n f " << a << ´ ´ << b << ´ ´ << c << ´\ n´;
                 re tu rn b;
                 r et ur n b
        }
        in t ma in
        i nt m ai n()
        {
              St ri ng x, y;
              S tr in g x y
               co ut       Pl ea se en te r tw o st ri ng s\ n";
              c ou t << "P le as e e nt er t wo s tr in gs \n
              ci n
              c in >> x >> y   y;
              co ut        in pu t:
              c ou t << "i np ut " << x << ´ ´ << y << ´\ n´;    \n
              St ri ng
              S tr in g z = xx;
                    f(x y)
              y = f x,y ;
               if x       z) co ut       x co rr up te d!\ n";
              i f (x != z c ou t << "x c or ru pt ed \n
               x[0
              x 0] = ´!´;
               if x       z) co ut       wr it e fa il ed \n
              i f (x == z c ou t << "w ri te f ai le d!\ n";
               co ut       ex it                                    \n
              c ou t << "e xi t: " << x << ´ ´ << y << ´ ´ << z << ´\ n´;
        }
      St ri ng
This S tr in g lacks many features that you might consider important or even essential. For example,
it offers no operation of producing a C-string representation of its value (§11.14[10], Chapter 20).


11.13 Advice [class.advice]
[1]    Define operators primarily to mimic conventional usage; §11.1.
[2]                             co ns t
       For large operands, use c on st reference argument types; §11.6.
[3]    For large results, consider optimizing the return; §11.6.
[4]    Prefer the default copy operations if appropriate for a class; §11.3.4.
[5]    Redefine or prohibit copying if the default is not appropriate for a type; §11.2.2.
[6]    Prefer member functions over nonmembers for operations that need access to the representa-
       tion; §11.5.2.
[7]    Prefer nonmember functions over members for operations that do not need access to the repre-
       sentation; §11.5.2.
[8]    Use namespaces to associate helper functions with ‘‘their’’ class; §11.2.4.
[9]    Use nonmember functions for symmetric operators; §11.3.2.
[10]   Use () for subscripting multidimensional arrays; §11.9.




       The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
            Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
298     Operator Overloading                                                               Chapter 11



                                                              ex pl ic it
[11] Make constructors that take a single ‘‘size argument’’ e xp li ci t; §11.7.1.
                                                     st ri ng
[12] For non-specialized uses, prefer the standard s tr in g (Chapter 20) to the result of your own
     exercises; §11.12.
[13] Be cautious about introducing implicit conversions; §11.4.
[14] Use member functions to express operators that require an lvalue as its left-hand operand;
     §11.3.5.


11.14 Exercises [over.exercises]
1. (∗2) In the following program, which conversions are used in each expression?
          st ru ct
          s tr uc t X {
                   in t i;
                   i nt i
                   X(i nt
                   X in t);
                   op er at or in t)
                   o pe ra to r+(i nt ;
          };
          st ru ct
          s tr uc t Y {
                   in t i;
                   i nt i
                   Y(X
                   Y X);
                   op er at or X)
                   o pe ra to r+(X ;
                   op er at or in t()
                   o pe ra to r i nt ;
          };
          ex te rn      op er at or X, Y)
          e xt er n X o pe ra to r*(X Y ;
          ex te rn in t f(X
          e xt er n i nt f X);
          X x=1   1;
          Y y=x   x;
          in t     2;
          i nt i = 2
          in t ma in
          i nt m ai n()
          {
                     10
                i + 1 0;              10
                                  y + 1 0;         10 y;
                                               y + 10 * y
                x+y+i    i;       x*x+i       f(7
                                          i; f 7);
                 f(y
                f y);             y+y y;     10 6 y;
                                             1 06 + y
          }
   Modify the program so that it will run and print the values of each legal expression.
                                  St ri ng
2. (∗2) Complete and test class S tr in g from §11.12.
                         IN T                             in t.             IN T: op er at or in t().
3. (∗2) Define a class I NT that behaves exactly like an i nt Hint: Define I NT :o pe ra to r i nt
                         RI NT                      in t
4. (∗1) Define a class R IN T that behaves like an i nt except that the only operations allowed are +
                                                                                     RI NT op er at or
   (unary and binary), - (unary and binary), *, /, and %. Hint: Do not define R IN T::o pe ra to r
   in t().
   i nt
                          LI NT                     RI NT
5. (∗3) Define a class L IN T that behaves like a R IN T, except that it has at least 64 bits of preci-
   sion.
6. (∗4) Define a class implementing arbitrary precision arithmetic. Test it by calculating the facto-
             10 00
   rial of 1 00 0. Hint: You will need to manage storage in a way similar to what was done for class
   St ri ng
   S tr in g.




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
Section 11.14                                                                                  Exercises     299



                                              St ri ng
7. (∗2) Define an external iterator for class S tr in g:

          cl as s St ri ng _i te r
          c la ss S tr in g_ it er {
                  // refer to string and string element
          pu bl ic
          p ub li c:
                   St ri ng _i te r(S tr in g& s)
                  S tr in g_ it er St ri ng s ;       // iterator for s
                   ch ar ne xt
                  c ha r& n ex t();                   // reference to next element
                // more operations of your choice
          };

    Compare this in utility, programming style, and efficiency to having an internal iterator for
    St ri ng                                                        St ri ng
    S tr in g (that is, a notion of a current element for the S tr in g and operations relating to that ele-
    ment).
8. (∗1.5) Provide a substring operator for a string class by overloading (). What other operations
    would you like to be able to do on a string?
                           St ri ng
9. (∗3) Design class S tr in g so that the substring operator can be used on the left-hand side of an
    assignment. First, write a version in which a string can be assigned to a substring of the same
    length. Then, write a version in which the lengths may differ.
                                        St ri ng
10. (∗2) Define an operation for S tr in g that produces a C-string representation of its value. Discuss
    the pros and cons of having that operation as a conversion operator. Discuss alternatives for
    allocating the memory for that C-string representation.
11. (∗2.5) Define and implement a simple regular expression pattern match facility for class S tr in g. St ri ng
12. (∗1.5) Modify the pattern match facility from §11.14[11] to work on the standard library s tr in g.  st ri ng
                                                           st ri ng
    Note that you cannot modify the definition of s tr in g.
13. (∗2) Write a program that has been rendered unreadable through use of operator overloading
                                                                             IN Ts
    and macros. An idea: Define + to mean - and vice versa for I NT s. Then, use a macro to define
    in t             IN T.
    i nt to mean I NT Redefine popular functions using reference type arguments. Writing a few
    misleading comments can also create great confusion.
14. (∗3) Swap the result of §11.14[13] with a friend. Without running it, figure out what your
    friend’s program does. When you have completed this exercise, you’ll know what to avoid.
                           Ve c4                       fl oa ts.           op er at or       Ve c4
15. (∗2) Define a type V ec 4 as a vector of four f lo at Define o pe ra to r[] for V ec 4. Define opera-
    tors +, -, *, /, =, +=, -=, *=, and /= for combinations of vectors and floating-point numbers.
                             Ma t4                          Ve c4              op er at or             Ve c4
16. (∗3) Define a class M at 4 as a vector of four V ec 4s. Define o pe ra to r[] to return a V ec 4 for
    Ma t4
    M at 4. Define the usual matrix operations for this type. Define a function doing Gaussian elim-
                    Ma t4
    ination for a M at 4.
                             Ve ct or            Ve c4
17. (∗2) Define a class V ec to r similar to V ec 4 but with the size given as an argument to the con-
               Ve ct or Ve ct or in t).
    structor V ec to r::V ec to r(i nt
                            Ma tr ix             Ma t4
18. (∗3) Define a class M at ri x similar to M at 4 but with the dimensions given as arguments to the
                   Ma tr ix Ma tr ix in t,i nt
    constructor M at ri x::M at ri x(i nt in t).
                              Pt r_ to _T                                                  Pt r_ to _T
19. (∗2) Complete class P tr _t o_ T from §11.11 and test it. To be complete, P tr _t o_ T must have at
    least the operators *, ->, =, ++, and -- defined. Do not cause a run-time error until a wild
    pointer is actually dereferenced.




    The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
         Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.
300     Operator Overloading                                                              Chapter 11



20. (∗1) Given two structures:
          st ru ct      in t x, y;
          s tr uc t S { i nt x y };
          st ru ct      ch ar p; ch ar q;
          s tr uc t T { c ha r* p c ha r* q };
                                                                       T,
    write a class C that allows the use of x and p from some S and T much as if x and p had been
    members of C C.
                                   In de x
21. (∗1.5) Define a class I nd ex to hold the index for an exponentiation function
    my po w(d ou bl e,I nd ex                        2**I      my po w(2 I).
    m yp ow do ub le In de x). Find a way to have 2 I call m yp ow 2,I
                         Im ag in ar y                                             Co mp le x
22. (∗2) Define a class I ma gi na ry to represent imaginary numbers. Define class C om pl ex based on
    that. Implement the fundamental arithmetic operators.




      The C++ Programming Language, Third Edition by Bjarne Stroustrup. Copyright ©1997 by AT&T.
           Published by Addison Wesley Longman, Inc. ISBN 0-201-88954-4. All rights reserved.

				
DOCUMENT INFO
Shared By:
Stats:
views:34
posted:6/19/2011
language:English
pages:40
Description: Technology,Computer,E-book,Solfware,C Programming Language_ch7,C Programming Language_ch8,C Programming Language_ch9,C Programming Language_ch10,C Programming Language_ch11,C Programming Language_ch12