As an IT professional with some 'Working Papers' on my web site and an interest in Object Orientated techniques, I feel I must write something on this topic! I will not attempt a textbook, of course. Nevertheless we can review some basic principles and emphasise a few key points.
There are those who would get all 'philosophical' when talking or writing about this subject. These are people to beware of! Although Object Orientation [perhaps we'd better say simply 'OO' from now on] gives ample scope in certain respects for a theoretical treatment, most of the time, plenty of pragmatism is advisable since the foundations are very practical.
First and foremost, OO is a software engineering technique which defines a particular way of structuring software; of building software in a modular fashion. In this way of building software, the code is organised on the basis of classes of object, such that the functions and data directly relating to a class are grouped around that class, or are said to 'belong' to that class. A class is just a generic type; an object is an instance of a class. (The class "Car" has for instance the specific car with registration XYZ as an object belonging to that class.) Because a class has both characteristic functions and characteristic data, we may tend to emphasise one of those two aspects when defining classes for a particular application. If we think first of the data aspect, the thought or design process is very like the data modelling idea of a traditional database system. For instance, we might identify "Car" as a class because we know we want to store data such as registration number, registered owner, colour etc. relating to all cars. From a more functional point of view, we would think about functions such as "change owner", "mark as stolen", etc.
In essence, that's all OO is! It isn't anything else! Certainly some years ago when OO was less well known, one might have believed, for instance, that OO is a functional characteristic of a system - as though, by observing the functionality of a system, one could tell whether it was object oriented or not. This of course is rubbish. OO is a characteristic of the way in which the software has been built and says absolutely nothing about the visible functionality. One can examine source code and say whether it is written on OO principles or not; if one cared to analyse the object code generated by compilation of the source, it would already be pretty difficult to get any clues [other than on the basis of the style of variable names] as to whether it was object oriented or not.
One of the problems with popularity is careless abuse! Because of the awareness of OO techniques, people recognise objects in everything. To a certain extent, they are right - but that is very different from characterising something as Object Oriented (with capital O's!) in the sense of the software engineering technique we should all mean by this term. Even well-respected authors describe the Windows Application Programming Interface (Win32) as being 'object oriented'. In a sense, it is based on objects (small o's) such as windows, display contexts, controls etc. However, in the correct software engineering sense it is not OO. This sort of confusion is unfortunate because it weakens the true concept.
Returning to my simple definition of OO (modules based on the concept of classes of object), there is of course a little more to it. It turns out that the simple concept is very powerful - that's why people are given to philosophising about it. The main thing that object classes lead to is the idea of "inheritance" - the idea that, having defined a class, we can recognise and define variants which share the same properties or characteristics with the first class but add some specific further details to form a new, 'more specialised' class. For instance, class "Taxi" might be based on (inherited from or derived from) the class "Car" by adding some further data and/or functions. So a specific taxi has all the data and function characteristics of a car but adds some more things (like taxi licence number etc.).
As a 'new' way of structuring or modularising software [O.K., it's 20 years old by now], it has proved to be effective in making the software design clear and therefore well maintainable and more reliable. But any highly modular way of building software should share these characteristics to some degree. It has also shown promise in making software more reusable, though so far the success in this respect has been limited (I come back to this later). What, more than anything, has made OO stand out as a technique is the way in which 'object oriented thinking' permeates the whole development process. Hence, for instance, Object Oriented system design has become prominent as preferred approach. And even at the system or functional specification phase one nowadays already begins to think in terms of objects or classes. This is important because it unifies the whole software development process. It breaks away from the old methodologies whereby a system was modelled in one or more ways before software production began, and such models bore little resemblance to each other nor to the resulting code, so that 'translation' or 'interpretation' of the models was a source of possible errors or confusion. Now there is a consistency of approach which benefits the whole process.
Furthermore, the approach is very 'natural', once one gets into it. In analysing a situation with the goal of providing computer-automated support, what is more natural than to make an inventory of the real-world participants in that domain with a view to modelling the relevant characteristics and behaviour directly within the proposed system? This very clear mapping between real world and internal model is clearly a great benefit.
So, should all software production now be Object Oriented? Yes! is the simple answer. At least, any new development, unless there's a very good reason not to do it this way. It is however neither necessary nor generally desirable to convert existing software to an OO structure. 'Converting' code to OO means almost certainly a virtual re-write and carries more risk than benefit. New code really ought always to be OO, even if an extension to an existing, non-OO system, if feasible. There is nothing in principle wrong with a 'partially OO' system. Obviously, the programming environment has to allow such a mixture, but even the introduction of a couple of object classes into an otherwise global domain is likely to have a beneficial effect. It certainly shouldn't be seen as some sort of heresy just because the system is not 'fully' OO.
Yes - why not? C++ supports a perfectly 'respectable' OO approach to software construction. It is powerful, flexible and popular. The above question tends to arise however because C++ might be considered not 'purely' OO; that is, it doesn't force the programmer to work in an OO way. Some languages (e.g. Small Talk, Java) are purely OO in the sense that every line of code written by the programmer necessarily belongs to one or other class. Such 'purity' has its drawbacks, however, such as limiting the programmer to classes which are already available in the same environment for support in the application environment - which support may or may not be up to the standard available outside that environment. This has been a problem certainly in earlier versions of Java when building Windows applications. Besides, the flexibility of C++ in providing access to non-OO services and not insisting on total OO is in my opinion a great strength.
It is worth mentioning in this context that a purely OO language does not necessarily enforce or encourage a good OO approach to software structure. I suspect a certain tendency in Java, for instance, for the main application or applet class to become the container for the total program functionality, thus treating the one class as representing the entire program. To the extent that this happens (other than for trivially small programs, of course) it does not represent good OO practice. (This is not meant as a criticism of Java!)
One specific aspect which one could argue is less well developed in C++ is the concept of the 'Interface'. Implicit in the modular approach is the idea of software interfaces between the modules. These should be simple and clearly defined. The concept also can be seen as an enhancement of the idea of encapsulation of the implementation: the user of a module - or more strictly, the user of the services provided by a module - should not have any concern for the implementation; he only wants to know what the interface is to these services. Java, amongst others, gives explicit expression to the concept of an interface. The concept is however by no means entirely absent in C++. Here, the interface of a class is implicit in the access rules and in the class declarations contained in header files: the interface can be considered to be the collection of all the class elements which have 'public' access. Furthermore, the 'abstract base class' in C++ provides a mechanism for defining services (an interface) in isolation from an implementation of them.
In summary, C++ is a perfectly good language for a programmer who knows what he's doing to build good OO software.
A 'complaint' one sometimes hears about the whole OO approach is the supposed difficulty in making a good choice of 'object' (object classes). Whilst it is certainly true that defining classes can lead to difficult decisions about where to draw the boundaries (e.g. deciding which services are supported by which classes), I think nevertheless that the problem can be exaggerated. From a practical or functional point of view, the classes of a system can be divided in two main categories: application ('problem') domain classes; and auxiliary classes. In the application domain, the choice of object classes really should be pretty straight forward. We are about to develop a system which will meet the functional requirements in a particular problem domain. Within that domain will be the objects with which the system will be concerned and which it will therefore model internally. Most of them should be pretty obvious! In as far as the problem domain might be a little more complicated than I am perhaps giving it credit for, the exercise of recognising relevant object classes is actually a very similar one to that of recognising 'entities' for the data model of a traditional database system. For a database system, it is a question of recognising the truly relevant entities - that is, things for which we can anticipate that we will need to include them in the database because we will want to store data relating directly to them. If that sounds long-winded, what I really mean is that we should avoid the danger of including things in the data model simply because 'they are there', even though we cannot think of any attributes of these things that we will need to store. Well, choosing application domain object classes for an OO system is basically the same exercise. Which things are relevant? If, for a potential class, we can't think of any attributes we would define for it, it very probably is not relevant.
The next step of course is to recognise not only the object classes but also the functional relationships between them (again, paralleling the equivalent exercise for a data model). But I don't want to go too deeply into the OO design process. The second category of object class I referred to was 'auxiliary'. By this I mean all the classes that 'spring up' in modularising the whole software system, after taking account of the application objects. These might be storage access classes, or classes concerning resource management generally or any utility services one might think of. These classes can be more of a problem because they arise out of design decisions - for particular services one is often faced with the choice of whether to define a separate class for them or not. This is a practical decision of whether to split a module into two or not. Here, one's 'gut feel' or common sense must often be the guide to determine whether an extra class adds to the "aesthetic beauty" of the design and does not merely complicate things unnecessarily. It's worth pointing out though that the choice of classes, both application and auxiliary, is a pragmatic one and that mistakes can be corrected quite easily in many cases. That is one of the advantages of the modular OO approach: because of the overall 'neat' structure, it is usually easy to modify, even when the modification concerns the correction of a mistake.
A further question we might handle here is: are there applications which are not suited or less well suited to the OO approach? Above I said that all new software ought to be built on OO principles - and I stand by that. Having said that, I suppose the obvious sort of application that lends itself less readily to this approach is the scientific or academic 'number-crunching' application. This would typically be a large block of code making extensive use of a library of mathematical functions. Nevertheless, the larger the problem is, the more it will probably benefit from being 'modularised', in which case it might as well be on an OO basis. And even a mathematical library is a set of services - encapsulate it in a class!
That aside actually leads me to another categorisation of classes: data-based and function-based. When conceptualising classes, for some we tend to place the emphasis on the data. These are usually the application domain objects which we wish to model by maintaining their data states; the functions associated with them generally support this state maintenance. For others, the emphasis is on the functions: we recognise that a logical set of functions is required and as such should be encapsulated in a class. Generally, these are auxiliary classes.
This distinction highlights yet another categorisation: 'one-off' or 'few'; and 'many'. Some classes in a system are there to be instantiated just once - the program will normally create just one object of that class. One reason to do this is when the class concerned is really just a set of functions (services) which need to be made available to the application and clearly, this 'making available' only needs to be done once. Classes which are instantiated a small number of times generally represent auxiliary objects like windows on a screen or file streams etc. Classes for which many objects will typically be created are usually the application domain 'data-centric' classes. We might be modelling Cars, Aircraft, Mail Pieces, Customers - whatever; typically we will be maintaining data - or a state - for a large number of them.
When we talk of 'components' in the sense usually meant by the term 'Component Technology', we mean something slightly different from what I have been talking about so far. The object classes I have meant above are software constructs defined in the programming environment, and specifically as interpreted by the compiler. We might call this the 'compilation domain'. When working with components as meant by the COM or CORBA technologies, we are talking about objects in the form of separate executable modules or tasks in the run-time environment. To really appreciate the difference, we need to just think about what is going on when a program is executed in an OO environment.
I have remarked that a program built using OO principles cannot in any way be distiguished from other programs purely on the basis of its functional behaviour. (By 'functional behaviour' I mean the behaviour as observed by any user of the program.) Can it be distinguished in any other way? Well, if were we able to look impartially at what is going on 'inside the computer' (specifically, in its memory), we would see in a normal program instructions being executed sequentially, occasionally branching, accessing data in the data segment or from the stack, and calling subroutines. A program built using OO techniques (in the complilation domain) does the same. However, one extra characteristic might become apparent: it will be continually creating small data structures in the data segment (or on the stack), closely followed by subroutine calls which include a pointer to such a structure as the first argument (or parameter) to the call. This is the behaviour of an OO program: it executes instructions sequentially or with local branching, until it requires services that are provided by another object class. It then creates an object of that class and uses the associated services in the form of subroutine calls. So an OO program is continually creating objects (or obtaining a reference to an existing object), using their services and then deleting objects that are no longer required.
A program that participates in a run-time component technology environment behaves in the same way as I just described. It creates objects, uses their services, and deletes objects that are no longer needed. The difference lies in the mechanisms involved. Creating this sort of object is a somewhat more complicated action than creating a little data structure in one's own data segment and then accessing its services by means of pre-compiled function calls. The purpose of component technology is to make standard services available on-line, in the real-time environment, to 'users' (other programs) via a standard interface which hides from the user any details of implementation, including the location where the services reside (local, in another process space or on a remote machine). Creating an object of this sort typically requires a system call, which, using the unique component identifier supplied by the user, locates the object server responsible for this object class, ensures that this server program is running and finally passes to it the request to create the required object. The user program receives then a reference to the object which it can use to access the services (in the case of COM in a C++ environment, the reference is a pointer and the services are accessed as function calls using the C++ virtual function call mechanism).
Obviously, the user program making use of component technology services has to contain the support for this way of working from the user (client) perspective. If the program is built using compile domain OO techniques, then it will be creating and using objects in the two ways I have described: its 'own' internal objects whose definition was implicit at compile time, and external objects supplied by other program modules whose services are accessed in a more complicated way.
I have gone into the foregoing detail because the question perhaps arises as to the difference between the 'two sorts' of OO, especially since my initial strict definition of what OO is might seem to exclude component technology. I defined OO as a software engineering technique for building modular software. In that definition I have primarily in mind the structuring implicit in the constructs supported by the particular language and compiler (e.g. C++). Nevertheless, separately built executable modules co-operating in the same way (albeit, via a somewhat 'heavier' mechanism) clearly also constitute a form of Object Orientation, and I have no problem in referring to it as such! Note that the participants in a component technology environment may themselves have been built individually using non-OO techniques, using for example C or FORTRAN (although in practice C++ makes it easier to use COM). So we could characterise the difference as one of level: the compile domain OO, at the level of compiled modules, might be considered the lower level OO; whilst component technology broadens the concept and can be seen as a higher level structure.