C++ and Object Orientation

Introduction to C++

C++ is an object-oriented programming language built on the base of the C language. This chapter gives you a very brief introduction to C++, touching on many important aspects of C++, so you would be able to follow our presentations of the C++ implementations of neural network models and write your own C++ programs.

The C++ language is a superset of the C language. You could write C++ programs like C programs (a few of the programs in this book are like that), or you could take advantage of the object-oriented features of C++ to write object-oriented programs (like the backpropagation simulator of Chapter Backpropagation). What makes a programming language or programming methodology object oriented? Well, there are several indisputable pillars of object orientation. These features stand out more than any other as far as object orientation goes. They are encapsulation, data hiding, overloading, polymorphism, and the grand-daddy of them all: inheritance. Each of the pillars of object-orientation will be discussed in the coming sections, but before we tackle these, we need to answer the question, What does all this object-oriented stuff buy me ? By using the object-oriented features of C++, in conjunction with Object-Oriented Analysis and Design(OOAD), which is a methodology that fully utilizes object orientation, you can have well-packaged, reusable, extensible, and reliable programs and program segments. It’s beyond the scope of this book to discuss OOAD, but it’s recommended you read Booch or Rumbaugh to get more details on OOAD and how and why to change your programming style forever! See the reference section in the back of this book for more information on these readings. Now let’s get back to discussing the great object-oriented features of C++.

Encapsulation

In C++ you have the facility to encapsulate data and the operations that manipulate that data, in an appropriate object. This enables the use of these collections of data and function, called objects , in programs other than the program for which they were originally created. With objects, just as with the traditional concept of subroutines, you make functional blocks of code. You still have language-supported abstractions such as scope and separate compilation available. This is a rudimentary form of encapsulation. Objects carry encapsulation a step further. With objects, you define not only the way a function operates, or its implementation, but also the way an object can be accessed, or its interface. You can specify access differently for different entities. For example, you could make function do_operation() contained inside Object A accessible to Object B but not to Object C. This access qualification can also be used for data members inside an object. The encapsulation of data and the intended operations on them prevents the data from being subjected to operations not meant for them. This is what really makes objects reusable and portable! The operations are usually given in the form of functions operating upon the data items. Such functions are also called methods in some object-oriented programming languages. The data items and the functions that manipulate them are combined into a structure called a class. A class is an abstract data type. When you make an instance of a class, you have an object. This is no different than when you instantiate an integer type to create variables i and j. For example, you design a class called ElectronicBook, with a data element called ArrayofPages. When you instantiate your class you make objects of type ElectronicBook. Suppose that you create two of these called EB_Geography and EB_History. Every object that is instantiated has its own data member inside it, referred to by ArrayOfPages.

Data Hiding

Related to the idea of encapsulation is the concept of data hiding. Encapsulation hides the data from other classes and functions in other classes. Going back to the ElectronicBook class, you could define functions like GetNextPage, GetPreviousPage, and GetCurrentPage as the only means of accessing information in the ArrayofPages data member, by functions that access the ElectronicBook object. Although there may be a hundred and one other attributes and data elements in the class ElectronicBook, these are all hidden from view. This makes programs more reliable, since publishing a specific interface to an object prevents inadvertent access to data in ways that were not designed or accounted for. In C++, the access to an object, and its encapsulated data and functions is treated very carefully, by the use of keywords private, protected, and public. One has the opportunity to make access specifications for data objects and functions as being private, or protected, or public while defining a class. Only when the declaration is made as public do other functions and objects have access to the object and its components without question. On the other hand, if the declaration happens to be as private, there is no possibility of such access. When the declaration given is as protected, then the access to data and functions in a class by others is not as free as when it is public, nor as restricted as when it is private. You can declare one class as derived from another class, which will be discussed shortly. So-called derived classes and the declaring class do get the access to the components of the object that are declared protected. One class that is not a derived class of a second class can get access to data items and functions of the second class if it is declared as a friend class in the second. The three types of declarations of access specification can be different for different components of an object. For example, some of the data items could be declared public, some private, and the others protected. The same situation can occur with the functions in an object. When no explicit declaration is made, the default specification is as private.

Constructors and Destructors as Special Functions of C++

Constructors and destructors are special functions in C++. They define how an object is created and destroyed. You cannot have a class defined in a C++ program without declaring and defining at least one constructor for it. You may omit declaring and then defining a destructor only because the compiler you use will create a default destructor. More than one constructor, but only one destructor, can be declared for a class.

Constructors are for the creation of an object of a class and for initializing it. C++ requires that every function has a return type. The only exceptions are constructors and destructors. A constructor is given the same name as the class for which it is a constructor. It may take arguments or it may not need them. Different constructors for the same class differ in the number and types of arguments they take. It is a good idea to provide for each class at least a default constructor that does not take any arguments and does not do anything except create an object of that class type. A constructor is called at the time an object of its class is needed to be created.

A destructor also is given the same name as the class for which it is a destructor, but with the tilde (~) preceding the name. Typically, what is done in a destructor is to have statements that ask the system to delete the various data structures created for the class. This helps to free-up allocated memory for those data structures. A destructor is called when the object created earlier is no longer needed in the program.

Dynamic Memory Allocation

C++ has keywords new and delete, which are used as a pair in that order, though separated by other statements of the program. They are for making dynamic allocation of memory at the time of creation of a class object and for freeing-up such allocated memory when it is no longer needed. You create space on the heap with the use of new. This obviates the need in C++ for malloc, which is the function for dynamic memory allocation used in C.

Overloading

Encapsulation of data and functions would also allow you to use the same function name in two different objects. The use of a name for a function more than once does not have to be only in different object declarations. Within the same object one can use the same name for functions with different functionality, if they can be distinguished in terms of either their return type or in terms of their argument types and number. This feature is called overloading. For example, if two different types of variables are data items in an object, a commonly named function can be the addition, one for each of the two types of variables—thus taking advantage of overloading. Then the function addition is said to be overloaded. But remember that the function main is just about the only function that cannot be overloaded.

Polymorphism and Polymorphic Functions

A polymorphic function is a function whose name is used in different ways in a program. It can be also declared virtual, if the intention is late binding. This enables it to be bound at run time. Late binding is also referred to as dynamic binding. An advantage in declaring a function in an object as virtual is that, if the program that uses this object calls that function only conditionally, there is no need to bind the function early, during the compilation of the program. It will be bound only if the condition is met and the call of the function takes place. For example, you could have a polymorphic function called draw() that is associated with different graphical objects, like for rectangle, circle, and sphere. The details or methods of the functions are different, but the name draw() is common. If you now have a collection of these objects and pick up an arbitrary object without knowing exactly what it is (via a pointer, for example), you can still invoke the draw function for the object and be assured that the right draw function will be bound to the object and called.

Overloading Operators

Inheritance

The primary distinction for C++ from C is that C++ has classes. Objects are defined in classes. Classes themselves can be data items in other classes, in which case one class would be an element of another class. Of course, then one class is a member, which brings with it its own data and functions, in the second class. This type of relationship is referred to as a “has-a” relationship: Object A has an Object B inside it.

A relationship between classes can be established not only by making one class a member of another but also by the process of deriving one class from another. One class can be derived from another class, which becomes its base class. Then a hierarchy of classes is established, and a sort of parent–child relationship between classes is established. The derived class inherits, from the base class, some of the data members and functions. This type of relationship is referred to as an “is-a” relationship. You could have class Rectangle be derived from class Shape, since Rectangle is a Shape. Naturally, if a class A is derived from a class B, and if B itself is derived from a class C, then A inherits from both B and C. A class can be derived from more than one class. This is how multiple inheritance occurs. Inheritance is a powerful mechanism for creating base functionality that is passed onto next generations for further enhancement or modification.

Derived Classes

When one class has some members declared in it as protected, then such members would be hidden from other classes, but not from the derived classes. In other words, deriving one class from another is a way of accessing the protected members of the parent class by the derived class. We then say that the derived class is inheriting from the parent class those members in the parent class that are declared as protected or public.

In declaring a derived class from another class, access or visibility specification can be made, meaning that such derivation can be public or the default case, private. The table shows the consequences of such specification when deriving one class from another.

Visibility of Base Class Members in Derived Class

Base Class Specification

Derived Class Access

private

none

protected

full access, private in derived class

public

full access, public in derived class

private

none

protected

full access, protected in derived class

public

full access, public in derived class

Reuse of Code

C++ is also attractive for the extendibility of the programs written in it and for the reuse opportunity, thanks to the features in C++ such as inheritance and polymorphism mentioned earlier. A new programming project cannot only reuse classes that are created for some other program, if they are appropriate, but can extend another program with additional classes and functions as deemed necessary. You could inherit from an existing class hierarchy and only change functionality where you need to.

C++ Compilers

All of the programs in this book have been compiled and tested with Turbo C++, Borland C++, Microsoft C/C++, and Microsoft Visual C++. These are a few of the popular commercial C++ compilers available. You should be able to use most other commercial C++ compilers also. All of the programs should also port easily to other operating systems like Unix and the Mac, because they are all character-based programs.

Writing C++ Programs

Before one starts writing a C++ program for a particular problem, one has to have a clear picture of the various parameters and variables that would be part of the problem definition and/or its solution. In addition, it should be clear as to what manipulations need to be performed during the solution process. Then one carefully determines what classes are needed and what relationships they have to each other in a hierarchy of classes. Think about is-a and has-a relationships to see where classes need to defined, and which classes could be derived from others. It would be far more clear to the programmer at this point in the program plan what the data and function access specifications should be and so on. The typical compilation error messages a programmer to C++ may encounter are stating that a particular function or data is not a member of a particular class, or that it is not accessible to a class, or that a constructor was not available for a particular class. When function arguments at declaration and at the place the function is called do not match, either for number or for types or both, the compiler thinks of them as two different functions. The compiler does not find the definition and/or declaration of one of the two and has reason to complain. This type of error in one line of code may cause the compiler to alert you that several other errors are also present, perhaps some in terms of improper punctuation. In that case, remedying the fundamental error that was pointed out would straighten many of the other argued matters.

The following list contains a few additional particulars you need to keep in mind when writing C++ programs.

  A member x of an object A is referred to with A.x just as done with structure elements in C.

  If you declare a class B, then the constructor function is also named B. B has no return type. If this constructor takes, say, one argument of type integer, you define the constructor using the syntax: B::B(int){whatever the function does};

  If you declare a member function C of class B, where return type of C is, say, float and C takes two arguments, one of type float, and the other int, then you define C with the syntax: float B::C(float,int){whatever the function does};

  If you declare a member function D of class B, where D does not return any value and takes no arguments, you define D using the syntax: void B::D( ){whatever the function does};

  If G is a class derived from, say, class B previously mentioned, you declare G using the syntax: class G:B. The constructor for G is defined using the syntax: G::G(arguments of G):B(int){whatever the function does}. If, on the other hand, G is derived from, say, class B as well as class T, then you declare G using the syntax: class G:B,T.

  If one class is declared as derived from more than one other class, that is, if there are more than one base class for it, the derivations specification can be different or the same. Thus the class may be derived from one class publicly and at the same time from another class privately.

  If you have declared a global variable y external to a class B, and if you also have a data member y in the class B, you can use the external y with the reference symbol ::. Thus ::y refers to the global variable, whereas y, within a member function of B, or B.y refers to the data member of B. This way polymorphic functions can also be distinguished from each other.

This is by no means a comprehensive list of features, but more a brief list of important constructs in C++. You will see examples of C++ usage in later chapters.

Summary

A few highlights of the C++ language are presented.

  C++ is an object-oriented language with full compatibility with the C language.

  You create classes in C++ that encapsulate data and functions that operate on the data, and hiding data where a public interface is not needed.

  You can create hierarchies of classes with the facility of inheritance. Polymorphism is a feature that allows you to apply a function to a task according to the object the function is operating on.

  Another feature in C++ is overloading of operators, which allows you to create new functionality for existing operators in a different context.

  Overall, C++ is a powerful language fitting the object-oriented paradigm that enables software reuse and enhanced reliability.