ECE 161: Programming Languages

Fall 2005

Monday 5:00 - 6:00 Rm 643E, Wednesday 3:00 - 5:00 Rm 621E

Click here for main page of course...

Topic #8: Classes

A class is a concrete representation of a concept. If you are familiar with structures (e.g., in C), you may want to start off thinking of a class as a generalization of a structure. (In fact, in C++, a structure is just a class in which everything is public by default.) A class is a definition of a type including member variables and member functions (a.k.a. methods). A member function is a function that is called through an object (an instance of a class).

In the latest addition of The C++ Programming Language by Stroustrup (the creator of C++), he claims that the primary reason for classes is to allow a programmer to create new types that are as convenient as provided types. My own impression (and that of other programmers whom I asked) is that, while important, this is not the primary importance of classes. In my mind, classes, and object-oriented programming in general, has provided a new paradigm of thinking when it comes to programming. Object-oriented programming shifts the focus of programming, to some extent, towards planning and organization of a program, and therefore away from just the algorithm used to implement an idea. Data structures and algorithms, which are very related to each other, have always both been recognized as crucial components of any program, but in my opinion, object-oriented program is responsible for a slight shift in importance towards the former and away from the later. When it comes to this last point, I'm not sure if other programmers would necessarily agree! Planning and organization in general, however, is now clearly more important, and a good object-oriented design makes it easier to share code and, perhaps even more importantly, expand a program later.

I have already mentioned that a class represents a concept. What classes to create when writing a program is a difficult question, but one approach is to think about the task abstractly and ask yourself what concepts are involved. For example, if you were writing a chess program, you might want classes to represent concepts such as board, computer, human player, piece, turn, game, etc. Whether or not you would have classes for individual types of pieces (e.g., pawn, knight, bishop), as opposed to just having the more general class for a piece, is arguable. In our lectures, we have primarily relied on the concept of a date, and a corresponding Date class, to cover many class-related concepts in C++.

Once a class is defined, the programmer should be able to declare, create, initialize, use, and manipulate, objects of the class without being aware of the internal structure. For this reason, member variables and member functions have different modes of protection. A private member variable can only be seen by member functions of the class (friends will be an exception discussed later), whereas public member variables can be seen outside the class and accessed through an object of the class. Private member functions can only be called by other member functions, whereas public member functions can be accessed through an object outside the class. (Public variables or member functions that are static can be accessed through the class itself, as opposed to being accessed through an object, which is, once again, an instance of the class; there exists only one copy of a static member variable for a class, and it is shared by all objects of the class.) Both member functions and member variables are private, by default, unless explicitly declared to be otherwise. (In addition to public and private, a third level of protection is called "protected". A protected member is private to things outside the class, but public to derived classes, a notion that is discussed later.)

The definition of a class starts with the keyword "class", followed by the name of the class, then a list of member variable and member function declarations within enclosing curly braces, and then a semi-colon. Typically, member functions are declared inside the class definition but defined outside of it. You can define a member function inside the class definition, but if so, it automatically becomes an "inline" function. (The inline keyword can be applied to any function definition, not just member functions of classes.) This means that calls to the function within the program are not true function calls; i.e., there is no activation record created. Instead, a copy of the code implementing the function is created at compile time and placed at the location of the function call. This can save time since there is no activation record created, and therefore less overhead at the start and end of the function execution, but on the other hand, the code can be much longer (which can slow it down, since there will be more cache misses and page faults when the program runs). Typically, it is only a good idea to make a function inline if it is both short and commonly used.

A constructor is a special member function of a class that is called once for every object when the object is created. A default constructor would allocate memory for the object but do nothing else. As with other functions (and member functions), a constructor can be overloaded; that is, you can create multiple constructors, and which constructor is called depends on what arguments are passed in. It is also possible to provide default values for arguments to constructors or other functions, so that if certain arguments are not provided, the corresponding parameters will be assigned the default values. We have seen this applied to our Date class, which also uses a static member variable to represent a default date that is used when certain arguments are missing.

In addition to overriding the default constructor, the programmer can also override the copy constructor or the copy assignment function. The copy constructor is called when an object is declared and assigned a value of another object at the same time; the regular copy assignment function is used otherwise. They must be defined separately. Often, the default behavior, which simply allocates space for every member variable and copies values is fine, but this is not the case when pointers are involved, unless you want the fields of different objects to point to the same memory. We will talk more about this as part of the next topic.

A few other class-related concepts have been discussed as part of this topic. Destructors are called when an object is destroyed (e.g., if the program leaves its scope); often you want a destructor to clean up memory pointed to be member variables of an object. Member functions can be declared "const", which means they are not allowed to change an object. Often they are used to allow a programmer to retrieve a private piece of a class. A const object can only access const member functions. Whenever a member function is called, the variable "this" automatically exists, and it points to the object through which the member function has been called. Sometimes this is used to refer to private member variables that have been hidden by a parameter with the same name, and sometimes it is used to return a reference to the object; e.g., when an assignment operator is overloaded (operator overloading is discussed as a separate topic).