Lecture 1: Introduction to Object-Oriented Programming and C++


Lecture 1: Introduction to Object-Oriented Programming and C++


This lecture owes a lot to the following article which I used as a handout for the course:
Tim Corson and John D. McGregor, "Understanding Object-Oriented: A Unifying Paradigm", Communications of the ACM, Vol. 33, No. 9 (September 1990).
1.1 Administrative Stuff
  • IDs and handouts.
  • Student information sheet.
  • Course outline with special attention to homework expectations, compiler requirements, examples offer.
  • Outline contents of Programming Environment Introduction. Special attention to 'script' command, printer usage, g++ compilation and debugging facilities. Athena programming environment. Athena Rules of Use.
  • Instructions on registering for and setting up accounts. Register for accounts last half hour of class.
1.2 C++ Functionality Hierarchy
  1. C subset
  2. "Better C" enhancements (e.g. referring to structs etc. with tags)
  3. classes
  4. data abstraction (enhancing classes with operator overloading)
  5. derived classes (inheritance, polymorphism, dynamic binding)
  6. templates and exceptions (not really OOP related)
  7. standard C++ libraries
1.3 Object-Oriented Programming Concepts
object 
a (possibly disjoint) region of memory
The pattern of bits indicates the object's state.
method 
a service provided by an object
This is a routine associated with an object that alters its state, provides information about it or provides a management service.
encapsulation 
procedures are bound to data, and a limited interface is provided for interacting with an object
Interaction with an object is limited to invocation of its methods. Direct modification of internal data structures, as is permitted with data members of C structs, is not allowed.
message 
the means provided for invoking an object's methods
In a C++ program, messages are function calls. Think of a function call as a synchronous message.
class 
a description of the data structures, methods and default values for a type of object
An object is referred to as an instance of a class to indicate that its behaviors and interface are determined by that class.
inheritance 
what happens when a class incorporates another class as part of its description
The incorporating class is called the derived or sub class. The incorporated class is called the base or super class. In this way, the derived class can incorporate the data structures and methods of a base class simply by mentioning the name of the base class in its description.
polymorphism 
a capability which allows an instance of a derived class to be used wherever an instance of the base class is required
dynamic binding 
the response of an object to a method invocation can depend on its class rather than the base class it is currently being treated as
data abstraction 
selected methods for new data types defined by a programmer can be explicitly related to each other and/or existing standard methods for pre-defined types
Definitely a focus in C++ although perhaps not in all object-oriented languages. In C++, the standard methods are equivalent to the standard operators, and operator overloading is the primary means by which data abstraction is achieved, although consistent naming conventions for methods is another possible route.
Here `abstraction' means "the act of separating the inherent properties of something from the concept to which they belong", `inherent' meaning "existing as an essential characteristic". In this case, the "properties" are the operations the class supports which are related to operations supported by built-in types. These relationships are made explicit with a thoughtful use of operator overloading. The standard operators act as tags for related inherent properties.
Example
UIComp class hierarchy
struct Rect {
  int m_x, m_y, m_width, m_height;
  Rect(int x, int y, int width, int height):
    m_x(x), m_y(y), m_width(width), m_height(height) { }
};
 
class UIComp { // user-interface component (abstract)
  char *id;
  Rect dim;
  // ...
public:
  UIComp(const char *name);
  const char *name() const { return id; }
  virtual void redraw() const = 0;
  virtual void resize(const Rect &) = 0;
  // ...
};
 
class UICompMgr : public UIComp { // manager of components (abstract)
  UIComp ** list; // array of pointers to components managed
  int size;
  // ...
public:
  UICompMgr(const char *name);
  void add(UIComp *);
  // ...
};
 
class UIRowCol : public UICompMgr {
  Policy policy;
  // ...
public:
  enum Policy { Matrix, PackRow, PackCol };
  UIRowCol(const char *name, Policy pol = Matrix);
  Policy InqPolicy() const { return policy; }
  void resize(Rect &);
  // ...
};
 
class UIPrim : public UIComp { ... }; // non-manager components
 
class UIValuator : public UIPrim {
  // component to retrieve value from user
  int value;
  ...
};
 
class UIBar : public UIValuator {
  // value between max and min
  int max, min;
};
 
class UIDial : public UIValuator {
  // wrap around values
  int scale;
};
 
UIRowCol panel("panel");
UIComp *comp = &panel; // in C:  comp = (UIComp *)&panel;
comp's "static" type is UIComp *. This is the class of the "accessed sub-object". This type never changes, it's static. comp's "dynamic" type is UIRowCol * at this point. This is the class of the "complete object" a sub-object of which has been accessed. Also called the "most derived class" for the object. This type will change depending on what comp points to.
cout << "This component's name is " << comp->name() << '\n';
  // calls UIComp::name() - binding made at compile time
comp->resize(Rect(10, 10, 300, 400));
  // calls UIRowCol::resize() - binding made at run time
  // using info stored with object (typically ptr to table of func ptrs)
1.4 Entities and Relationships
The object-oriented programming paradigm takes programming technique to a new level. The procedural paradigm concentrates on flow diagrams and stepwise refinement (blocks in blocks etc.) of a particular task. The object-oriented paradigm concentrates on entity-relationship diagrams; however procedural techniques can still be useful when implementing the methods for an "entity" (another word for class, although in some contexts it might mean an object). (Intersection example from CACM article).
Three important relations between classes:
1. is_a (or isa) - inheritance relation between classes
Example:
class left_turn_light : public light {
  // ...
};
A left_turn_light is a light.
2. is_part_of (or hasa - reversed sense but same idea) - contained by another object -- containing object has exclusive use -- actually just a stronger case of (3) below
Example:
class Car { Wheel wheels[4]; };
A Car has a Wheel. A Wheel is part of a Car.
3. usage - other classes/objects a class/object interacts with. This is a catch-all for everything which doesn't fit into 1 or 2.
Example:
UICompMgr keeps a list of components which it repositions and resizes using their resize methods. Access is undoubtedly not exclusive. (Other classes need to access a managed component to fulfill its primary purpose in life which is to facilitate interaction with the user. The UICompMgr just manages its layout with respect to other components, so it wouldn't make sense to give it exclusive access to the managed components.) So this is a usage relationship. In an entity relationship diagram, this would appear as:
usage relationship:  UICompMgr --resizes--> UIComp
1.5 Advantages of OOP
  1. Re-use of code. Linking of code to objects and explicit specification of relations between objects allows related objects to share code. Encapsulation and weak coupling between objects means class definitions are more likely to be re-used in other applications. Objects as well as procedures (focus of C libraries) become likely candidates for re-use. The enforcement of a consistent interface to objects lessens code duplication.
  2. Ease of comprehension. Structure of code and data structures in it can be set up to closely mimic the generic application concepts and processes. High-level code could make some sense even to a non-programmer. The analysis/design/coding phases in development become more seamless since they can all deal in the same concepts.
  3. Ease of fabrication and maintenance (redesign and extension) facilitated by encapsulation, data abstraction which allow for very clean designs. When an object is going into disallowed states, only its methods need be investigated. This narrows down search for problems.
1.6 C++ Objectives
  1. extend C to allow for object-oriented programming
  2. other improvements - some resulting in deprecation of some C facilities
  3. remain compatible and comparable (syntax, performance, portability, design philosophy - don't pay for what you don't use, don't get stuck with things you don't need) with C
  4. emphasize compile-time type checking
C++ is multi-paradigm. It provides for the object-oriented approach but doesn't enforce its use. This makes it a good transition language and gives it flexibility when a particular situation doesn't fit the object-oriented philosophy.
With this object-oriented approach, C++ overcomes certain shortcomings of C:
  • Lack of encapsulation means that if an object is getting trashed, it's difficult to find the code responsible. Many procedures may have had idiosyncratic interactions with the object.
  • Doesn't recognize relationships between types. Pointer casting necessary. In C++, pointer casting can just about always be dispensed with. Pointer casting is a kludge. Compiler can't check if you are doing it correctly. No type safety (see definition below).
  • Not easy to extend existing libraries; for example, make it so printf() can handle new types.
  • Except for FILEs, there are no well-developed objects (like stacks and lists) in the standard libraries.
C's future is as a portable "universal" assembler, a back end for code generators.
While any C++ compiler should be able to compile a C program successfully with minor changes, several aspects of C programming are discarded in the transition to C++: new facilities are supplied for I/O, memory allocation and error handling; macros and pointer casts become obsolete for the most part.
type safe 
situations in which an object is used in a way which is incompatible with its type are quickly detected
In C and C++, the primary incompatible usages of concern are passing an object as an argument to a function which is expecting some other unrelated type of object, or attempting to access members which don't exist.
1.7 Other Object-Oriented Languages
Objective C
CLOS (Common Lisp Object System)
Ada 9X
FORTRAN 90
Smalltalk
Modula-3
Eiffel 

0 comments: