2000 Feb 21
These terse notes are not a substitute for reading the textbook. The textbook provides many more examples and explanations. These are a rough draft of my lecture notes.
A type is a group of elements and permitted operations on them. A class is a user-defined type. It consists of a group of objects and permitted operations.
Write a short English description of the class's purpose and then write code using the class from a user's point of view. This reveals what public functions the class must provide.
After this point, there is no need to look at the use code.
Write a short English description for how to implement the class. For example, ``Our shopping cart's contents will be stored in a vector of pairs, each storing an item's name and price.''
I suppose it would be useful to document this design decision as a comment in the code.
Public members can be accessed by users of a class. Private members cannot be accessed by users of a class. They exist to ease implementation. For example, if a helper function would be useful, there is high probability it should be a private member function.
Summary:
C++ designer Stroustrup writes that ordinary member functions have three logically distinct properties:
We will now consider writing functions without all three properties. Static member functions have only the first two properties: They can access public and private portions and are inside the class. Friend member functions have only the first property: They can access public and private portions.
When using a member function, we must specify which object to use. For example, to invoke the size() member function on the goo object, we use goo.size(). When defining a member function, we are given ``free'' access to the ``current object'' (called *this in C++). Conceptually, when we move from the user's point of view to the implementor's point of view, we move from using an explicit object goo to the implicit ``current object.''
The current object stores its values for the class variables. For example, in the shopping cart definition, insert's definition uses the private variable items residing in the object for which insert was invoked. In an ordinary member function, if a variable is not defined in the function as either a local variable or a parameter, the current object is searched for the variable.
Conceptually, one way to view member function invocation such as goo.size() is as invoking size with a hidden first argument of the goo object. Thus, conceptually, goo.size() is equivalent to size(goo). This may help understand why a C++ compiler gives strange error messages sometimes.
Static class members can access both the private and public portions of a class and are members of the class, but they are not invoked using an object. Because they are not invoked using an object, they cannot use the current object to look up values for class variables such as items described above.
To define a static member function, prefix the word static to the beginning of the member function definition. Be sure the definition does not access any non-static members, but it may access both private and public static members. In other words, it may not access any variables whose values are stored in the current object.
To invoke a static member int foo(int x) defined in a class goo,
Use a static member whenever you want to write code that is independent of any particular object in the class. One frequent use is to define helper functions for use with STL functions. These helper functions usually can have only a fixed number of parameters and we want to ignore the hidden ``current object'' parameter that would be present if we used a member function.
A friend function is a function logically associated with a class that is not a member of the class but still needs access to private portions. For example, the output operator operator<< for the shopping cart class needs access to the private vector of items in the shopping cart but cannot be a member function because of the way the iostream library is constructed. Looking at the code for operator<<, we see that it does access the private items portion of its shoppingCart argument sc, e.g., sc.items.begin().
Even though friend functions are not part of the class, their definitions can appear directly inside the class if desired. Just prefix the definition with friend. Make sure that they access only static class members or use an object passed as an argument to access the private parts.
The public and private labels do not impact friends since they are not class members.
Friend functions should be used when a function needs access to the private portion of a class or one of its objects, but the function cannot or should not be part of the class. Common examples include input and output operators. Another use is for binary operators for which both parameters have equal importance so, if it was written as a member function, it would not be clear which parameter to use as the hidden current object.
Overloaded functions are two or more functions with the same name but different parameters. The parameters must differ in number and/or type. (Differing only in return type is not sufficient.) For example, the STL function sort takes either two or three arguments, depending on whether one specifies a comparison operator.
Use overloaded functions when two or more functions perform the same task, but different functions are needed to handle different parameters.
Almost all C++ operators can be defined for use with classes. We introduce the syntax by example: bool operator||(const foo & f, const foo & g). Since || for built-in types takes two arguments, it must take two arguments when overloading it. At least one of these two arguments must be a user-defined type; otherwise you would be trying to redefine the operation on two C++ built-in types.
Overloaded operators that are class members have one fewer parameters than if they were not class members. For example, if you decide to make operator! a class member, it will take no arguments, while, if not a class member, it would have one argument. This is because class members have a first parameter of the hidden current object.
Tips:
It is an art, not science, to decide whether a function should be overloaded, given an operator name, be a friend or static function.