Starting out with low-level machinecode, different programming languages and programming paradigms have been developed over time. A lot of the currently used programming languages use object oriented programming in different forms.
Before newer programming languages adopted the object-oriented paradigm of programming, programming languages were essentially based on separated models for the data that needed to be processed and for the functions (algorithms) which processed the data.
For example, if you wanted to calculate something using complex values (which have a real and an imaginary part, leading to the need for two different variables for each complex number value), you would define a simple structure with two floating point variables, and then write a bunch of different functions for adding, subtracting, multiplying and dividing complex values. If your program also had similar sounding computing functions for some other functionality, it was easy to confuse which function to use where in the main program.
For simpler applications, this works quite well, but with more processing power and ever more functionality (like graphical user interfaces), it's hard to keep up. As more functionality is added to an application, this often requires more data to be processed, leading to more variables and more complex data structures. Often enough, functions end up being written for processing different chunks of related data, with the source code for these appearing far away from each other. This makes it more and more difficult to analyze and extend the program when additional functionality has to be added later on (especially if this has to be performed by a different programmer).
The problems with the earlier programming languages led to the development of a new programmig paradigm in the form of the object-oriented model.
Independent of the details of the actual programming language being used, the object oriented programming method starts with the idea that practically everything that surrounds us in real life can be described as some kind of object.
Each class of object can be described by a name and has one or more properties. An object can also perform specific functions - described by methods - which either change the state of the object itself, the state of another, related object, return some kind of information or process related data. Objects of a similar kind - e.g. cars produced by different companies - can be part of the same class of object. In a similar way, specific classes of objects can be derived from more generic object classes - for example, cars and trucks are different, but both are (motorized) vehicles.
Depending on the class definition and implementation, objects can often also send and recieve messages from other objects - either objects of the same type or objects from another type. This is useful to implement a flexible handling of individual states of the objects and the application, which is especially needed for complex systems with parallel processes and thinks like graphical user interfaces.
Object class definitions in programming combine the definition of the data structure with the definition of the functions - here called "methods" - which process the data.
Coming back to the example of writing a program to process complex numbers, a class for complex numbers would include both the variables for the real and the imaginary part of the number, as well as the methods for adding, substracting, multiplying or dividing two (or more) complex numbers. Looking at the kind of necessary computations for computing something with complex numbers, you would also add methods for doing calculations with a complex number and a real, floating point number, as well as converting a complex number into the alternative combination of angle and radius (distance) and back.
All of the necessary functions (methods) for working with complex numbers are then part of the object class "complex number". Instead of defining several variables and separate functions for your complex numbers, you would just define a new object of the related class, which automatically includes all the necessary properties and methods for different kinds of calculations. This makes it much easier to handle different kinds of objects and access their individual functions.
Similar to real life objects, object class definitions in a program can inherit properties and methods from other, more generic object classes. Most object oriented programming languages offer some way of controlling, which parts of an object class can be inherited by derived object classes, and in which way.
As an example, let's say that there is a generic object class "vehicle" with some base definitions:
Vehicle class properties:
Vehicle class methods:
Now, we can define a class for "motorized vehicle" based on this with some additions:
Motorized vehicle class properties:
Motorized vehicle class methods:
With that, we can define more specific classes for "car" and "truck", but also for "bus" or "train" as well as "airplane". Each of the derived classes inherits some shared parameters and generic methods, which can be used to model more specific functionality.
Since the basic functionality behind methods like "move" in the above example is the same for all objects of the different types (like cars and trucks), it only needs to be implemented in code once, as part of the original "vehicle" class. Inheritance allows the method to be used by objects of all derived classes. This way, the same functionality does not have to be rewritten several times, and errors in any method can be located much easier.
Some programming languages combine object oriented programming with the option of "operator overloading". This refers to standard mathematical operators like "+", "-", "*" and "/" which are abbrieviations for computing operations.
Since each operator essentially stands for a specific function, it is similar to a method of an object class. For numerical operations, numbers of any kind in combination with the operators form what is called a "group" in mathematics - since you cannot really do much with the definitions of the number set alone. Basically, the number set definition in mathematics is comparable to the definition of a data type in programming, and the numerical operators are similar to functions.
"Overloading" an operator just means that a class defines a method for some kind of computation which uses a mathematical operator as its method name. When you define several objects of this class, you can then use this method by simply writing down the equation as you would do with a simple number. Once you use a standard operator in combination with two or more of these objects, the self-defined computation method for the class will automatically be used instead of the normal numerical computation.
All in all, object-oriented programming is just one of several different programming paradigms. It is definitely one of the most useful and flexible ways for programming so far.