Skip to main contentCal State San Bernardino / [CNS] / [Comp Sci Dept] / [R J Botting] >> [CSci202] >> abstraction
[Index] [Schedule] [Syllabi] [Text] [Labs] [Projects] [Resources] [Search] [Contact] [Grading]
Notes: [01] [02] [03] [04] [05] [06] [07] [08] [09] [10] [11] [12] [13] [14] [15] [16] [17] [18] [19] [20]
Thu Apr 19 08:51:48 PDT 2007

Contents


    Abstract Classes

      Definitions

      Abstraction is the process of omitting details. We need this to understand complex objects. Modern programming and modelling languages help us by providing the ideas of an abstract class and an abstract operation.

      An abstract class is a class that has one or more abstract operations. An abstract operation is not implemented in its class but in classes that are derived from it. A class with no abstract operations is called a concrete class. An abstract class defines an incomplete framework into which you can plug in specific implementations.

      One abstraction can have many different internal structures - and different performance properties. For example: A Stack can implemented by using an array or by using a linked list. It is nice to be able to express an abstraction when we are programming a complex problem. Several object-oriented languages allow you to define an abstract class and derive from it multiple implementations.

      For example, the class of Animals may be abstract class and Lion may be derived from it. The Abstract Animal has an operation that returns the number of legs. Lions implement this legs() operation as returning the number 4. Similarly, a Snake has 0 legs, and a Bird 2 leg. Here is the UML diagram of the abstract class Animal with abstract operations. The italic names indicate abstract classes and operations in the UML. The diagram also shows that Lion, Snake, and Bird implement the abstract class. The dashed generalization arrow indicates this.

      UML diagram of Animal, Snake, and Bird

      [ animal.dia ]

      An object that is declared to be in a concrete class (a Snake, Lion, or Bird above) has defined behavior. If the concrete class implements or relizes an abstract class then the object must satisfy the abstract operations. So Animal above is realized or implemented by Lion, Snake, and Bird.

      On the other hand you can not create an abstract object. Instead we define pointers that refer to the abstract type but are attached to objects in concrete classes that implement the abstract class. All animals share the legs() abstraction so we can point at any Animal and say "How many legs has that Animal got?":

       	Animal *thatAnimal;
       	Lion leo;
       	thatAnimal = &leo;
       	cout << thatAnimal->legs() << endl;

      Analogies

      An abstract class gives us a view of an object from a distance. Concrete classes are up close and personal. From a distance we can see an Animal with legs that feeds on food. Only when we get closer can we see that the animal is a Bird with 2 legs and a liking for bugs.

      In most places in the world you can ask for a GlassOfBeer. The ammount of beer you get is different: The UK Pint is larger than the USA pint, and the metric half-liter is larger still. Still you order by the "glass". So GlassOfBeer is an abstract class that is realized differently in each country. Indeed in Geneva (Switzland) the size of a GlassOfBeer varies with the part of town you are in.

      You can think of an abstract class as a socket into which you plug in code. The abstract functions are holes in the socket. The prongs in the plug are the concrete functions. The abstract class serves to organize a set of functions that are implemented in many different ways. It sets a standard that different implementations must meet. It is like a standard wall socket or jack - nothing happens unless a working device is plugged into it.

      C++ Abstractions

      In C++ we signal that a class is abstract by using pure virtual functions. A pure function in C++ is a member function of a class that is not implemented in that class. In C++ all pure functions must be declared as virtual. For this reason C++ programmers talk about pure virtual functions rather than abstract functions.

      We use normal inheritance to encode the implementation of an abstract class.

      The concrete classes derived from the abstract class must overload all the pure functions and so define what the function does on objects in the derived class. Realization and implementation fill in the missing details.

      The behavior of an object is defined by its concrete class. Clearly the behavior of objects in abstract classes is not defined unless they are also in a derived concrete class. So it is not possible to declare objects as elements of abstract classes. We can not do this:

       	Animal x; // ERROR
      To declare an object in an abstract class is like buying a watch that has nothing inside it.

      Neither can we ask for a new one to be created:

       	Animal * p = new Animal; //ERROR
      However we can have a pointer declared to point at the base class, which actually points at an object that is in a derived class
       	Animal * p = new Lion; //OK!
      Thus abstract classes are used by using pointers in place of objects. This is why in C++ you make all the pure functions virtual as well. This makes sure that the correct implementation is always chosen via a pointer to the abstract class. The compiler can sort out direct references before the program starts. The virtual functions will figure out the concrete class as the program runs.

      Next, you make sure that it is impossible to create objects that are in the abstract class, except by declaring one of the implementations.

      The C++ syntax is odd. (1) All functions in the abstract class must be declared as virtual. (2) At least one function is declared as being equal to zero! (3) The rest must be given implementations.

       	class Animal{
       		public:
       			virtual int legs()=0;//this is not a mistake!
       			virtual void feed(Food)=0;//output a noise?
       			...
       	};
      In Animal above the meaning of feeding an animal and the number of legs it has are deferred to a derived classes:
       	class Lion : public Animal {
       		public:
       			virtual int legs(){return 4;}
       		...
       	};
       	class Snake: public Animal{
       		public:
       			virtual int legs();
       	};
       	int Snake::legs(){return 0;}
       	...
      It is now possible to declare Snakes and Lions but we can not declare an Animal. However we can declare variable that points to an Animal and make it point at either a Snake or a Lion. The following uses cassert to test the classes:
       		// Animal a; -- illegal
       		Snake s; // legal
       		Lion l; // legal
       		Animal * p; // legal
       		p=&s; //p is the address of s, *p is s.
       		assert( p->legs() == 0 );
       		p=&l; //p is the address of l, *p is l.
       		assert( p->legs() == 4 );
       		cout << "Test OK" << endl;
       		return 0;
      You can find a simplified demonstration of these classes by downloading [ animal.cpp ] and testing it. If that is OK, try an array:

       		Animal * zoo[]={new Lion; new Snake, new Bird};

      Money as an Example

      Money is an abstraction, Dollars, Franks, Pounds, Punts, etc etc are all concrete realizations of the idea of Money. This inspired the following pieces of code: [ moneyv.h ] [ moneyv.cc ]

      Concrete, Abstract, and Interface

      We call a class with no pure virtual functions a concrete class. We call a class with nothing but public pure virtual functions an interface. Classes that have some pure functions and some fully defined and implemented functions "abstract classes".

      Interfaces

      An interface describes a set of functions that a class can use. It also define the set of functions that a class must provide if it is to be useful. The interface becomes usable when a concrete class is derived from it. However the code using an interface can be written and checked out by the compiler before the interface is implemented. Interfaces are useful because several different interfaces can be implemented by one class. Multiple inheritance is not a problem when there are many interfaces and one abstract or concrete base class.

      The UML Lollypop Notation

      Classes that relaize many interfaces are common in complex programs so there is a special short hand notation in the UML. A class that implements an interface has a lollypop (---0) growing out of it. The name of the interface is written by the lollypop. A class that uses the interface to access a class has a dotted line that points at the circle at the end of the lollypop.

      Animate is an interface for three other classes

      Abstractions that Share Data

      When a base class declares its public functions as virtual it allows its derived classes to provide a definition of what these functions actually do. Typically one base has several derived "subclasses" each with different implementations of the same set of functions. Sometimes it is natural for all the derived function to share some common properties. The case study in the text, for example, shows how circles and rectangles both have the attributes of area and perimeter, but calculate them differently.

      It is not wise to make data public. In this case (derived classes need access to their base class's data) therefore the data should be declared to be protected. Protected data (and functions) can be accessed by derived classes only. This provides a measure of encapsulation - protection from arbitrary changes - while permitting a degree of coupling between classes.

      Glossary

    1. abstract::=A description that leaves out unwanted detail but tells you enough to use the things described.
    2. abstract::Java=a class that has at least one pure virtual function.
    3. ADT::=Abstract data type is a class that specifies a collection of functions and operators and separately provides a file of implementations for these.

    4. interface::=a class which only has abstract operations.

    5. concrete::=the oposite of abstract, a concrete class which has no pure virtual functions.

    6. automagically::jargon=something that is automatic and so neat that it does precisely what you wanted as if it was magic.

    7. inheritance::= See http://csci.csusb.edu/dick/samples/glossary.html#inheritance

    8. polymorphically::=Automatically adjusting to many different shapes by using polymorphism.
    9. polymorphism::= See http://csci.csusb.edu/dick/samples/glossary.html#polymorphism

    10. pure::C++ = a virtual member function described as "=0;", hence an abstract operation.

    11. UML::= See http://csci.csusb.edu/dick/samples/uml.html

    12. virtual::C++=a magical incantation that makes a member function work polymorphically.

    . . . . . . . . . ( end of section Abstract Classes) <<Contents | End>>

    Abreviations

  1. TBA::="To Be Announced", something I have to do.
  2. TBD::="To Be Done", something you have to do.
  3. Dia::="A free Open Source Diagramming tool for Linux, Windoze, etc. ".

End