February 13, 2002
Reading assignment:
  Deitel and Deitel - read the last details of chapter 6, also 7.1-7.3
  -or-
  Wang 4.4-4.5, 5.4 (same as last lecture)

Warm-up and review:
  1.  What is wrong with the following code?
      string *s;
      cin >> *s; 
      Ans: s is a pointer to a string, but no string has been defined!
      Fix it like this:
      string *s;
      s = new string;
      cin >> *s;
  2.  What is the difference between an object and a class?
      Ans: A class is a type, an object is a variable of that type
      (an object is an instance of a class)
  3.  Say we have
      int arr[5]={1,2,3,4,5};
      int *ip = arr;
      int **ipp = &ip;
      How do I get the 3rd element of arr by using arr, ip, and ipp?
      ans:  arr[2];
            *(ip+2) or ip[2];
            *(*ipp+2) or (*ipp)[2];

Two more things from the Ratnum example:
  - Updated files for Ratnum class showing today's changes are
    ratnum2.h, ratnum2.cpp, testrat2.cpp
  - The constructor can be improved by having it take default parameters -
    then we can avoid having 3 versions.  Assign the default values in
    the class declaration (in the header file).
  - We'll also enhance Ratnum to be able to deal with constant objects

const objects, constant member functions
  - as with other types, an object can be const.  Const objects should
    always be initialized.  Here's an example:
    const Ratnum zero(0,1);
  - const objects can't call any of their member functions unless those
    member functions are also declared const.  A const member function
    isn't allowed to change any data in the object.
  - In Ratnum, we can make get_numerator(), get_denominator(),
    convert_to_double(), and display() all const member functions

const data members
  - you can declare a data member to be constant.  It can' be changed,
    but it can be set exactly once at initialization.  There is special
    syntax called "member initialization" syntax to handle that - it
    goes in the constructor, and MUST be present if you have const
    data members

Using the assignment operator
  - Say you have two objects of a class, called obj1 and obj2 and you say
    obj1 = obj2;
    Then every member of obj2 is copied into the corresponding members of obj1.
    In other words, the default assignment operator in c++ is memberwise copy.
  - If some of the members are pointers, this could be really really bad.
  - So we can override this default, and write our own assignment operator code.
    We'll learn how to do this in Chapter 8.

Copy constructor
  - When you call a function by value, a copy is made of the parameter.
    Similarly, when you return a value from a function, a copy is made.
    A third case when this happens is when you initialize a variable at
    the time of definition to be a copy of another variable.  The default
    for the compiler is to copy classes member-wise.  For now this is fine,
    but when a member is a pointer to dynamically allocated memory, then
    when we copy, both objects would point to the same memory.  The default
    for copying can be overridden, and we'll learn about this in Chapter 8.

Destructors
  - You can provide a destructor for the objet.  It has the name
    ~classname().  It doesn't destroy the object, rather it gets
    called when the object is destroyed, and gives you an opportunity to
    clean up.  Cleanup includes releasing dynamically allocated memory,
    thus avoiding memory leaks.  More on this in Chapter 7.

Classes that contains classes as members - composition
  - a class can have a member that is itself another class.
    enum Sex = {Female, Male};
    class Person {
        string first_name;
        string last_name;
        Ratnum age;
        Sex sex;
    };
  - Here's an example of how to use this class:
    Person John;
    John.first_name = "John";
    John.last_name = "Doe";
    John.age.set_ratnum(41,2); // he's 20 and a half years old
    John.sex = Female;   // Oops!  here's a mistake in our database!