Starting with Objects

A general rule of good program design (not always true, but worth considering) is that you should identify the objects in the real world, and make sure that each has a proper representation in the program. In the Goldfish Club (discussed presiously), the real world objects are people, goldfish, the person-goldfish relationship, and the club's membership list.
        People and Goldfish are solid unarguable objects, but some might argue about the relationship between a goldfish and a person. We are not concerned philosophical arguments about what makes an object. For us, an object is anything, concrete or abstract, that has some kind of existence and is of importance to our program. The connection between members of the Goldfish Club and their goldfish certainly qualifies.
        So we have four kinds of real world objects. None of them correspond to software objects in our program. Each person is certainly represented in the arrays, but there is no one thing that can be indentified as the representation of a person. We could say that the 73rd person in the club's records is represented by the collection of ten items <memnum[73], title[73], fname[73], lname[73], straddr[73], city[73], state[73], zip[73], phone[73], birthday[73]>, but that is not a single object, and it isn't even true anyway. If one person owns three goldfish, they will appear in the list three times, so their "representation" is spread over a number of ten-item groups. Imagine having to change a member's name (when he or she gets married or joins a new religion); there is no one place where the change could be recorded, and that is very strong evidence that there is no one object representing the person.
        All the other kinds of objects are in the same position. The information that is required for the object is present, but not in the form of a proper object. The main thing that C++ and other object oriented languages give us, is the ability to define proper objects.

        In C++, we could define new kinds of objects to represent people and goldfish quite easily. This is the syntax:
class Person
{ public:
    char *memnum;
    char *title;
    char *fname;
    char *lname;
    char *straddr;
    char *city;
    char *state;
    char *zip;
    char *phone;
    char *birthday; };
class Goldfish
{ public:
    char *name;
    char *species;
    char *birthday;
    char *birthyear;
    char *favcolour; };




    
The introduction: "class Person" simply says that we are defining a new class. Class is the C++ term for a "kind of object". The class called Person will be the representation for all persons, not just one. After these declarations, Person and Goldfish become new types, just like int and float, and we will be able to define variables that contain Persons just as we can define variables that contain integers: "int x;" and "Person x;" are both valid declarations, and mean more-or-less the same thing.
        The curly brackets are required to surround the parts that make up the class, otherwise they would look like normal declarations of global variables. The word "public" indicates that all of the parts about to be defined are generally accessible. It is possible to protect parts against accidental (or deliberate) changes by saying protected or private instead, but that will come later. The rest of the definition of the class is simply a list of normal variable declarations. They could have any types, and any names. In this example they are all char * because that's how they were in the previous example. It would be much more sensible to make some of them (such as memnum, birthday, and birthyear) into ints instead, and soon we will.
        Those class definitions do not define any variables at all. They do not create variables called title or birthday or any of the others. They simply specify that any time you create a variable of type Person, it will contain within it, sub-variables called title, fname, and so on. This little example shows what that means:
          Person a, b;
          a.title="Mrs";
          a.fname="Semolina";
          a.lname="Pudding";
          a.straddr="221b Baker St";
          a.city="Origami";
          a.state="MT";
          a.zip="83741";
          a.phone="2839981243";
          a.birthday="1225";     // i.e. 25th December
          b=a;
          b.title="Mr";
          b.fname="Poindexter";
          b.birthday="1031";
The only variables created in this example are a and b. Each of them have the nine defined parts that can be accessed individually as variables in their own right, but the object as a whole also has a real existence, as illustrated by the assignment b=a; which copies all of a's parts into b.
        It is absolutely not a problem that both Person and Goldfish have sub-variables called birthday. We are only allowed to access a subvariable in a context that makes the whole object obvious (e.g. in b.birthday="1031"; it is completely obvious that we are talking about b's birthday and nobody else's), so no confusion can ever occur.
        We can also have arrays of objects:
          Person people[100];
          people[1]=a;
          people[2]=b;
An object in an array is no different from an object in a variable of its own. We can access its sub-variables, assign it, or do anything else:
          for (i=1; i<=N; i+=1)
            printf("Person %d is %s %s\n", i, people[i].title, people[i].lname);
We can even have pointers to objects. In fact, objects are nearly always accessed through pointers, for reasons that will become clear later.
          Person *p;
          p=&a;
The normal syntax for accessing a sub-variable through a pointer is quite ugly. First we have to apply * to the pointer to find the object that it refers to, then we have to apply . to the object to reach the correct sub-variable:
          (*p).zip="65432";
so C gives us a combined notation for accessing a sub-variable through a pointer:
          p->zip="65432";
-> is an operator that combines *'s pointer-following and .'s subvariable-accessing into one.

Correct Terminology:
        
An Object is a single self-contained lump of data, whose real existence is totally internal to a program. a, b, and p in the above examples, are not objects. a and b are variables that contain objects (it is a very subtle distinction, but significant nonetheless); p is a variable that points to an object.
        A Class is a data type that represents all possible objects of a given kind. The relationship between Object and Class is the same as the relationship between the number 3 and the type int.
        A Member is what I have been informally calling a sub-variable. It is simply one of the named individual parts that make up an object or a class.


Now that we have good solid software objects to represent at least two of our real world objects, we would be sensible to start designing some functions to make programming with them more convenient. There are certain operations that are definitely going to be performed very frequently. For example, Printing a person's or a goldfish's details is probably going to be a very common task, so we would probably want to write:
          void print(Person p)
          { printf("%s %s %s of %s\n", p.title, p.fname, p.lname, p.city); }

          void print(Goldfish g)
          { printf("%s, a %s born is %s\n", g.name, g.species, g.birthyear); }
And we would instantly see that there is going to be some competition for the most popular function names. They can't both be called print (actually in C++ they can, but that is beside the point). C++ solves this problem by allowing functions to be members of classes, just like variables. A function that is a member of a class is properly called a Method of that class. To illustrate this, we'll redefine the two classes:
class Person
{ public:
    char *memnum;
    char *title;
    char *fname;
    char *lname;
    char *straddr;
    char *city;
    char *state;
    char *zip;
    char *phone;
    char *birthday;
    void print(void); };
class Goldfish
{ public:
    char *name;
    char *species;
    char *birthday;
    char *birthyear;
    char *favcolour;
    void print(void); };





   
void Person::print(void)
{ printf("%s %s %s of %s\n",
       title, fname, lname, city); }
void Goldfish::print(void)
{ printf("%s, a %s born is %s\n",
       name, species, birthyear); }
Whenever you want to put a method in a class, just put a prototype for the function inside the class definition, and a proper complete definition somewhere outside. The prototype "void print(void);" inside Person's definition is simply a promise that Person's own version of print will be defined at some point in the future. When that point in the future is reached, and we are ready to define the function, we have to make it clear which version of print is being defined. That is why the Person:: appeared in front of the name.
        In fact, Person:: isn't in front of the name, it is really part of the name. All members (and methods) of a class can only be accessed in a context that makes it clear exactly which object they are members of. Remember we have to say "a.fname"; just "fname" would not be allowed. Similarly, to print something, we aren't allowed to just say "print()", we must make it clear whose print method is being used: "a.print()". Whenever there is no object handy to make the distinction clear, we can use the member's full name instead; fname is just an abbreviation for the full name Person::fname.
        A method can only be called when it is clear which object's method is meant. That means that a method will only ever run when it is known which object it belongs to. That means that there is no need specify an object again inside a method. It is ok to say fname and lname alone.
        Here's how it works:
          Person her;
          her.title="Miss";
          her.fname="Frogalina";
          her.lname="Sprocket";
          her.city="Ouagadougou";
          her.print();
The statement her.print() means call Person::print, and give it the object her to work on, so inside print, any access to fname is automatically considered to be an access to her.fname, and everything works nicely.
        Methods are always called in connection with a particular object, and they always have direct access to that object's members. That is the real point of a class method.


        Another important concern is that all members of an object should be properly initialised before they are used. Not all members necessarily need initialisation, but some do. Suppose we failed to assign a string to her.city before calling her.print(). The function would have no way of knowing that anything is amiss, and it would attempt to print city as a string. Anything could happen, an uninitialised string is just a random pointer somewhere in memory.
        C++ gives us a way to ensure that all important members are initialised automatically every time a new object is created. This is done by defining a Constructor. A constructor is just a normal method or function with two special attributes. One is that it must have exactly the same name as the class that it belongs to; the other is that it must not have a return type, not even void. To add constructors to our two classes, we would add simple prototypes to the class definitions. Goldfish has this line added to it:
              Goldfish(void);
and Person has this line added to it:
              Person(void);
Then outside the class definitions, we provide the complete definitions for the two constructors. Remember that all we have to do is ensure that all the members are put in safe initial states; we don't need to put any useful information anywhere:
          Goldfish::Goldfish(void)
          { name=""; species="";
            birthday=""; birthyear="";
            favcolour=""; }

          Person::Person(void)
          { memnum="0"; title="Mr"; fname="No"; lname="Name";
            birthday=""; straddr=""; city=""; state=""; zip="";
            phone=""; }
These are very boring functions. The point is that they make programs safe. Every time an object is created, no matter how, its constructor is called. There is nothing you can do to prevent the constructor from being called. In fact, you are not allowed to create objects if their class hasn't got a constructor to call. So if we say:
          Person him;
          him.title="Prof";
          him.fname="Wally";
          him.lname="Drab";
          him.print();
even though we forgot to give a value to city, nothing would go wrong, because the constructor has already given it a default safe value.

        It is a bit wasteful to do all those assignments in the constructor if we haven't forgotten anything, because the very next statements will be assigning new values to those same variables. We could define an alternative constructor that is provided with parameters to tell it useful initial values to give to the members.
        This is how it would look:
          Person::Person(char *mn, char *tt, char *fn, char *ln)
          { memnum=mn; title=tt; fname=fn; lname=ln;
            birthday=""; straddr=""; city=""; state=""; zip="";
            phone=""; }
This constructor has four parameters, all strings. It can only be called if four string parameters are provided. That's no problem. When this sort of constructor is in use, declarations look like this:
          Person a("1231","Ms","Henrietta","Chicken");
          Person b("1232","Mr","Ivan","Itch");
The declarations look like function calls, which is exactly what they are. Variable declarations that look like this work just like any other variable declaration; they just allow parameters to be passed to the constructor.
        Surprisingly, we can have both kinds of constructor, and even more. So long as all the constructors for any class can be distinguished by their parameters (either by having a different number of parameters, or by having the same number but with different types) a class can have as many different constructors as you like,
        For an example, I'll give complete definitions for Person and Goldfish, showing exactly how they would appear in a program. We'll have three constructors for a Person, one to be used when we have no useful information yet, one for when we already know the person's name, and one to be used when we know their address too.
          class Person
          { public:
              char *memnum, *title, *fname, *lname;
              char *straddr, *city, *state, *zip;
              char *phone, *birthday;
              void print(void);
              void print_address_label(void);
              Person(void);
              Person(char *mn, char *tt, char *fn, char *ln);
              Person(char *mn, char *tt, char *fn, char *ln, char *sa,
                     char *ci, char *st, char *zi, char *ph, char *bi); };

          class Goldfish
          { public:
              char *name, *species, *birthday, *birthyear, *favcolour;
              void print(void);
              Goldfish(void);
              Goldfish(char *nm);
              Goldfish(char *nm, char *sp, char *bd, char *by, char *fc); };

          void Person::print(void)
          { printf("%s %s %s of %s\n", title, fname, lname, city); }

          void Person::print_address_label(void)
          { printf("%s %c %s\n", title, fname[0], lname);
            printf("%s\n", straddr);
            printf("%s, %s %s\n", city, state, zip); }

          Person::Person(void)
          { memnum="0"; title=""; fname="No"; lname="Name";
            straddr=""; city=""; state=""; zip="";
            phone=""; birthday=""; }

          Person::Person(char *mn, char *tt, char *fn, char *ln)
          { memnum=mn; title=tt; fname=fn; lname=ln;
            straddr=""; city=""; state=""; zip="";
            phone=""; birthday=""; }

          Person(char *mn, char *tt, char *fn, char *ln, char *sa,
                 char *ci, char *st, char *zi, char *ph, char *bi)
          { memnum=mn; title=tt; fname=fn; lname=ln;
            straddr=sa; city=ci; state=st; zip=zi;
            phone=ph; birthday=bi; }

          void Goldfish::print(void)
          { printf("%s, a %s, born in %s\n", name, species, birthyear); }

          Goldfish::Goldfish(void)
          { name=""; species="";
            birthday=""; birthyear=""; favcolour=""; }

          Goldfish::Goldfish(char *nm)
          { name=nm; species="";
            birthday=""; birthyear=""; favcolour=""; }

          Goldfish(char *nm, char *sp, char *bd, char *by, char *fc)
          { name=nm; species=sp;
            birthday=bd; birthyear=by; favcolour=fc; }
With these definitions in force, a program could correctly use all of the following. In every case, it can tell which constructor to call by the type of the variable being created and the number and types of the parameters provided:
          Person one("8239","Dr","Vera","Crooked");
          Person two("12312","Miss","Jellybean","Jones","11 A Av","Aack","AK","12345","1234567");
          Person three;
          Person four("9239","Uncle","Horace","Horse");
          Goldfish x("Goldie");
          Goldfish y("Yellowie");
          Goldfish z("Fluffy","Himalayan Blue","0231","1865","Purple");
          Person *p;
          p=&two;
One final observation about the last two lines. Constructors are called only when an object is created. The declaration Person *p creates a pointer that can point to an object, but it does not create an object. It is exactly the same as with all other pointer declarations. Declaring a pointer never creates an object, so it never causes a constructor to be called, so you are never allowed to provide parameters. The very last statement makes p point to an object that has already been brough into existence (seven lines before), so of course no constructor is called.

This is just the beginning. If things don't seem quite right, that may be because you haven't seen everything yet. Don't worry about it. This is quite enough new stuff for one week; we'll get to the rest soon enough.