An object is a Random-Access Machine.
The Random-Access Machine (RAM) is a theoretical model for the digital computer. It has a bank of addressed memory where it stores information, and a set of built-in commands which modify that information. The term 'random-access' means that you can read or write information to the memory addresses in any order, rather than having to step through them sequentially. Sequential-access machines would be those that step through the data one item at a time, like a queue, or moving forward and backward, like a stack.
(As an aside, the queue-based sequential-access machine is called a state machine. The stack-based sequential-access machine is called a pushdown automaton. A function that only stores information in one variable is equivalent to a state machine, and a set of nested functions, with input parameters and return values, is equivalent to a pushdown automaton. A set of functions that share two or more global variables are once again equivalent to a RAM)
An object is a RAM because it has a bank of addressed memory (its attributes) and a set of built-in operations that modify its information (its methods). The fact that an object's memory addresses tend to be human-readable names rather than numbers is irrelevant. So is the fact that different addresses (attributes) can store different data types. The whole 'numerically-addressed 8**N-bit registers' thing is just a convention that happened to be easy to burn into silicon.
An OO application is a network of Random-Access Machines.
The typical OO application consists of a set of objects that communicate by triggering each other's methods. Those objects share data in various ways, which are known as types of linking. The three most common types of linking are:
- Direct linking, also known as inheritance,
- Data linking, also known as shared memory,
- and Function linking, also known as input paramaters and return values.
Inheritance effectively embeds one RAM inside another. All the embedded RAM's memory and operations are accessible to the embedding RAM. The embedding RAM 'inherits' all the embedded RAM's storage and abilities, and can add further storage or abilities as the programmer sees fit. Inheritance creates the greatest amount of interdependence between the embedding RAM and the embedded one, therefore it is said to have the tightest coupling of the three types of linking.
Data linking makes one or more chunks of addressed memory visible to two or more RAMs. For unrestrained data linking, all the RAMs that share the memory can read or write data at any time. This can generate all sorts of problems with two or more RAMs trying to modify the same address at the same time, which are generally known as concurrency issues. You can control concurrency problems with locking protocols, but those get almost as hairy as concurrency problems per se. About the only safe way to handle data linking is to give one RAM the power to write to the address, and restrict all the other RAMs to read-only access. Because of these problems, data linking has the second-tightest coupling of the three linking methods.
Function linking has the loosest coupling of the three linking methods, because input parameters and return values impose automatic read-only constraints on the values being passed. Even within that realm, though, there are tighter and looser forms of coupling. Call-by-value likning is the loosest and most bulletproof form of linking currently available, because nothing actually travels between the caller and the callee. The application's runtime environment reads the value indicated by the caller, and writes a copy to the memory location of the callee's input parameter. Nothing the callee does can affect the caller's stored data in any way. Call-by-name linking (i.e.: passing a pointer) has tighter coupling than call-by-value, because once you dereference the pointer, you have to deal with all the problems of data linking again.
What all this has to do with the original question:
If you want to understand OO techniques, you have to know how objects work. Go back and take another look at CGI::Application, and look at the relationships between data storage and data manipulation. You can't grok the OO mindset if you only focus on the data or the manipulations. Look at who's responsible for what chunk of data, and how the various pieces communicate with each other. That should give you a better idea of what objects are, and why people choose to put feature X in class Y.