Do you already understand the principle of Object Based programming? Many people may tell you that they are one and the same thing, but really Object Oriented programming is an extension of the former.
In the world of procedural programming, things are pretty much broken down between data structures and behaviour (functions/procedures); your functions/procedures stand alone, and perform operations on your data.
e.g. a classic linked list header might look like
struct node { /* */ };
void add_to_list( node* head, data d );
void remove_from_list( node* head, data d );
data* find_in_list( node* head, data d );
void sort_list( node* head );
There's a straightforward pattern between each of those functions - their first argument always references the linked list structure in some way; The calling-convention will always look something like
node* head = create_node( 1 );
add_to_list( head, 2 );
add_to_list( head, 3 );
remove_from_list( head, 2 );
data* d = find_in_list( head, 1 );
sort_list( head );
In the world of object-based programming, the relationship between the data structure and the behaviour which operates on the data is acknowledged, then tightly bound together in the form of data structures which have both data and behaviour (a.k.a classes). The difference between object-based programming and procedural programming is extremely simple - it is nothing more than a different way to organise your code into logical units.
class linked_list
{
void add( data d );
void remove( data d );
data* find( data d );
void sort();
}
Compare that to the procedural solution - the main differences are
1) the functions exist inside a data structure
2) The functions no longer reference to the data structure in their arguments - because a reference to a data structure Object is implied by the way the function is used and the object is called, using the new calling convention...
linked_list my_list;
my_list.add( 2 );
my_list.add( 3 );
my_list.remove( 2 );
data* d = my_list.find( 1 );
my_list.sort();
Hardly revolutionary from a pure code point of view; but looking more closely at it, the code is now a little bit more organised. Not only this, there's no longer a concept of a 'head' floating around the main bit of code where the list is actually used!. The head is an implementation detail of the linked list.
In the procedural solution, the head is wide open for all to see, and there's nothing stopping a rogue bit of code from breaking the list.
Furthermore, programming languages which support classes tend to also help you isolate the memory management - with any luck, any heap-management is entirely self-contained within the depths of the class instead of in standalone functions.
Furthermore, the real benefit of approaching programming in this way is the benefit for the person designing it; You can "think bigger" than simply juggling characters, integers, arrays, structures, pointers, handles, etc;
Stepping away from the linked list example, think of GUI code - instead of worrying about API calls, resource lifetimes, callbacks, handles, etc, you can design code which says "First I'll create a Dialogue Box, then I'll add a button, then I'll link this button to a function/event".
Given the ability to create classes which represent real-world entities, you can write the code in a manner which fits far more closely to your problem domain; selectively ignoring all of the nitty-gritty-details, and working at a high level where concerns about precisely how a Window/Form/Button/Tickbox/etc functions is a problem to be solved elsewhere. There are a bunch of software-design principles associated with this kind of thing, but the main ones are Encapsulation and Separation of Concerns.
--
Note - this far I've only mentioned Object-Based programming; Object-Oriented programming takes it one step further, Although in my personal opinion, "Object Orientated Programming" (OOP) is perhaps the most widely-used and poorly-name software development concept ever uttered. (Others feel free to disagree, that's just my take on it)
- The real power and purpose of Object Oriented Programming has nothing (IMHO) to do with Objects and is not specifically about Programming. To my mind, "OOP" is about Designing to an interface (Maybe Interface Oriented Design would be a better name?)
The thing which separates "OOP" from Object-based programming is called Inheritance - it is the ability to specify a general-purpose class which is reused by other specialised classes.
going back to the linked list example - look at the functions
void add( data d );
void remove( data d );
data* find( data d );
void sort();
They belong to a linked list, but in fact, they should also be applicable to an array, a binary tree, a hashmap...
Suppose you have 4 different classes for each kind of data structure - you want to write a find-and-replace function which stands on its own and simply looks like
data* item = structure.find( something );
if ( item != NULL )
{
*data = replacement;
return true;
}
else
{
return false;
}
I guess it could be a standalone function, what does the signature for the function look like though? That logic applies to any structure which has a find(data) member, but if all you've got are a bunch of different data types, then you might end up doing something like
bool replace(void* structure, int structure_type, data something, data replacement)
{
if( structure_type == eLINKEDLIST ) // etc.
else if( structure_type == eARRAY ) // etc.
else if( structure_type == eBINARYTREE ) // etc.
Yuck, yuck, and more yuck! the code suffers from else-if-heimers disease (Where's the hashmap? Oops!) and looks like a dumping ground for special-case stuff. Furthermore, there might be a bunch of other identical chunks of code lying around im similar functions.
Inheritance to the rescue maybe? Well, a void* is unpleasant - it would be nice to be able to simply pass in a reference to a data type which simply provides access to the find function of any kind of data structure. Who cares whether its a linked list, an array, a hashmap. Most importantly, any code which uses too much if-else-if-else-if is usually a careless mistake waiting to happen
class interface_structure
{
virtual void add( data d );
virtual void remove( data d );
virtual data* find( data d );
virtual void sort();
}
Then all which is left to do is define each of the other structures
class linked_list : public interface_structure;
class hashmap : public interface_structure;
class array : public interface_structure;
class binary_tree : public interface_structure;
Now there's an obvious way to write the replace function. No need to figure out what the kind of structure is - replace() simply couldn't care, because it has been designed by way of selective ignorance:
bool replace( interface_structure* structure, data something, data replacement )
{
data* item = structure.find( something );
if ( item != NULL )
{
*data = replacement;
return true;
}
else
{
return false;
}
}
In fact, the replace function could possibly also be part of the interface structure (Which would turn the interface structure into an Abstract Base Class - that's a design choice which a programmer would be faced with. Standalone functions are not necessarily a bad thing).
As I hinted before, I don't believe the power here is necessarily in the programming - it's all in the design. "Object Oriented Programming" is a complete paradigm shift which requires that you re-learn how to approach problem solving all over again. You need to make the mental shift which ignores implementation detail and examines a program's behaviour at the higher level.
Designing OO code is all about identifying themes and commonalities across different "kinds of" entities; making the shift isn't something which happens straight away or naturally, but I believe you need to learn to "think" OO before you can program it. (But of course the programming practice is generally where the learning happens)
(There's a lot more to "Object based" and "Object Oriented" design/programming than this.. design patterns, S.O.L.I.D principles, and a whole bunch of other things. )