When programs grow: hundred of thousands of statements, the management become difficult with C-type languages. There are too many parts to manage, with too many correlations. A typical example of over-complex software is a graphical user interface, with a lot of intercorrelated elements: as windows, scroll bars, menu of different types, etc. Other examples are computer games, a very, very difficult and complex software.
The solution is to subdivide the problem in smaller parts, communicating with clear and standardized interfaces. Each part can be developed and can evolve in an autonomous way, as long as the interface doesn't change.
There is no support, in programs like FORTRAN or C, for this thing; a good solution for this problem is object oriented programming, introducing the concept of classes in computer languages.
Classes are similar to the structures of the C language: collections of heterogeneous things (named class members), but contain also the functions acting on them.
Some of the functions can be called outside the class and constitute what is called the interface of the class. They are refferd as "public members". Other functions are "private", used into the class, can't be wieved from the outside.
The programmer have to write a description of the class (the class declaration), usually placed in an header file. This description is used in the program to create object entities build with all the features of the class. These are named "instances" of the class; the class acts as a model for real object constructions.
By using the object oriented approach, a problem can be easily subdivided in smaller parts. It's not just a trick to make programming easier, it is also a different way of organizing the software structure and a new way to analyze the problems.
The focus is more on data than on procedures, and understanding the data and finding the best representation of data in term of classes is the key point of an object-oriented project.
This is not easy to do, and I've sometimes seen the object oriented approach leading to an over-structured software, an intricate beast impossible to manage. But, if used in the correct way, the object oriented approach is a very, very powerful tool.
Unfortunately, object programming is today also a common trend, all recent computer languages have classes, and object programming is used everywhere, most of times to add useless complexity to simple problems.
Classes where added to the C language by Bjarne Stroustrup, in the late seventies, Stroustrup took the classes from the Simula language and ported them to C, creating the language: "C with classes", to be used at the AT&T research laboratories. The language was renamed "C++" ,in 1983.
C++ is a language written by a programmer for programmers, with a very user-oriented approach, aimed at solving real problems and not designed following an abstract design scheme; moreover it was an extension of C, one of the most used language in that period. For these reasons C++ had a wide diffusion and became one of the most used object oriented programming languages.
It was the preferred language for games and user interfaces, but also many science projects migrated to C++, as many big software projects at CERN. The success of C++ greatly contributed to give big emphasis to object programming.
The addition of classes to C++ didn't lead to a very clear language structure, and C++ looses the elegant essentiality of C. There are a lot of subtle details in C++ classes usage; too many features added, and more are introduced at each release of the standard. Some features are complex and can lead to very intricate software, as: inheritance details, templates and operator overload.
C++ seems more a patchwork of all the possible features, rather then a well conceived project. Too many things have been stuffed into the simple and elegant C structure.
But C++ is still a good language, and it is compatible with C, being (nearly) a superset of the C language. And you don't need all the features of C++ to write good programs.
In fact, after a careful reading the books of Meyers [1], I decided not only that I don't need all the C++ subtleties, but also that relying on the fine details of a language is very dangerous. Your software risk to be linked to a specific implementation of the language, it is more complicated, more difficult to read and to modify, impossible to translate in another language, or to port to a different architecture.
In computer science "simple is beautiful"; software subtleties has to be avoided. With modern, fast computers, extreme efficiency can be happily given away in exchange of a simpler structure [2] ; the real hassle isn't software writing, but maintenance. Software should be written from the beginning with the idea of make maintenance easy.
Some features of C++, and in general of object oriented languages, worth to be mentioned here, because they are major steps toward a greater level of abstraction in computer programming:
function and variables are "closed" into the class objects and are not visible from the outside, except for some of them constituting the class interface.
This allows for a clean separation of the problem in independent parts. Function and variables of a class are called "members" of the class. Function are often referred to a "methods" of the class.
class can be build in an incremental way: a class can extend another class by adding and/or replacing some method with his own methods. One says that the class "inherits" another class, that becomes its "parent class"; the class which inherits is called the "derived class".
Inheritance is in principle a bad things, because it breaks encapsulation; and encapsulation is a fundamental pillar in the treating of a complex problems.
Sometimes you need to break encapsulation, but to avoid breaking more than needed, partial inheritance has been introduced: a member of a class can be declared "public", "private" or "protected". A private member is completely enclosed in his class, it is not even seen in the derived class. A public member is part of the interface of a class and can seen from all the program. A protected member is inherited, but not seen from the outside.
A derived class can be inherited, becoming the parent of an other class.
This can cause some ambiguities when a member is inherited, and then re-inherited and then re-re-inherited; to avoid problems a derived class can declare also how, in itself, the inherited members have to be considered. In this way a class can make private to itself all inherited members, or protected (if public or protected in the base class) or inherit in a public way, and in this case public members in the base class are public in the derived and protected are protected.
But things are more involved too: sometimes the programmer, when writing a class remember, remembers to have written the same functions for another class; why write the same function twice? C++ avoid this by introducing "friend classes"; friends share protected and private members. A class declares its own friends, in its definition: friends can be other classes or only an external functions. Each class must specify all its friends in its definition, but friendship could cause a big mess in inheritance, so it is stated that friends can't be inherited.
Class have constructor functions, called when an object is instantiated, and destructor, called when an object in deleted. Constructor and destructors are not inherited, and are automatically called when the derived class is deleted. But we can have more than one constructor, in this case a constructor without arguments should exist, this is the constructor called by default in these cases.
In C++ there is also multiple inheritance: a class can inherit more than one class; in this way the programmer can built all the intricate inter-correlations he can conceive, and also unthinkable ones, by mixing multiple inheritance and friendship at will. Many programmers enjoy doing that.
For people not accustomed to inheritance a little example of inheritance can be useful.
it is when the same interface is used for different objects
This is the real step toward the abstraction in computer programming, but it can be a bit more intricate than inheritance.
In C++ a class can be referred to by a pointer to its base class.
If I have two classes: "Square" and "Circle", and both inerith the class: "Figure" (see to the ineritance example); I can manage a figure without caring if it is a square of a rectangle. I can define a "makeArea" function both in the Square and in the Circle class, and computing the area in different ways without caring of the peculiarities of the figure, by calling the makeArea function by a pointer to the base class: Figure
This is a simple example, not explaining the power of this feature of the language, but, in real cases, as in computer games, this is a very important tool.
Imagine a game with many characters, as a warrior, a mage, an horse etc. You are describing a battle and want the killed warrior fall to earth, the killed mage explode and the horse being invulnerable. In C or old FORTRAN you should use a set of conditional statements to accomplish these tasks. If you have many, many characters, as in actual games, and many action beyond killing the character, writing all the clauses can be a nightmare. In C++ you can kill any character with a statement similar to:
Acharacter-> die() ;
And, if a mage, he will explode, if a warrior falls and if a horse nothing will happens. You can finally write "generic" battles that grately simplify the programmer life.
Here "Acharacter" is a pointer to a generic "Character" class, the Character class must have a function die(), declared as "virtual" . Virtual functions are functions which can be redefined in the derived class, but can be used by a pointer to the base class. If not declared "virtual" the pointer to the base class refers the member defined in the base class, not in the derived one.
The "Horse", "Mage" and "Warrior" are classes which inherit the "Character" class. In the Character class the virtual function: die() can do nothing; the Horse class will not redefine the die() function and will use the parent's one; instead the Mage and Warrior classes have their own die() function, and this specific function is called when they are killed.
Tho make things less simple, there are also "pure virtual" functions, abstract classes, virtual destructor and constructors of virtual classes, a complete set of specific rules for the inheritance of virtual things, and four or five different way of converting pointers involved in inheritance. Too long to be described here; a clean explanation is in: http://www.cplusplus.com/doc/tutorial/polymorphism/, but I want to remember that:
The pointer to the base class can be used only to access to members declared: virtual, they can't access non virtual members in the derived class.
An "abstract class" is a class containing a "pure virtual" functions: function without statements, as:
virtual void die()=0 ;
This function "must" be defined in derived classes.
An abstract class must be inherited,
and its function implemented in a derived class,
to be used.
Abstract classes are used to define interfaces
of classes before beginning to write code.
Useful in a top-down design of a complex software.
Another way of implementing polimorphist in C++ is the use of templates.
Templates are classes or function in which some types (integer, real, etc.) are defined at compiler time. In this way a single template is written, then the the compiler generates, from this single template, if needed, different functions, one for real, one for integer variables etc.. This is for writing less code, but the program becomes more difficult to debug.
This is polymorphism applied to operators. When writing a class, you can use the usual operator symbols, as: "+ - * / " to accomplish different things. For example, if you have a class describing a row of book on a scaffold you can define a "+" operator which takes 2 scaffolds, orders books by authors and put all the books togheter in a new scaffold. This simplifies the syntax of programs using classes.
This is not all, they are adding new particular features to C++ at any revision. We had a revision in 2014, another in 2017; for revision details see: https://isocpp.org/std/status
This text is released under the "Creative Commons" license. |