tl; dr: Você pode ter herança sem OO, pode ter encapsulamento sem OO, pode ter polimorfismo sem OO, pode até ter os três ao mesmo tempo sem OO. Por outro lado, você pode ter OO sem herança. Além disso, existem diferentes tipos de encapsulamento (orientado ao ADT e OO), nem todas as encapsulamentos são OO.
Versão longa:
O termo "Programação Orientada a Objetos" foi inventado por Alan Kay, então ele decide o que significa. E ele define desta maneira :
OOP para mim significa apenas mensagens, retenção e proteção local e ocultação de processos estatais e vinculação extrema de todas as coisas.
Em termos de implementação, o sistema de mensagens é uma chamada de procedimento com limite tardio e, se as chamadas de procedimento são limitadas com atraso, não é possível saber em tempo de design o que você chamará, portanto, não é possível fazer suposições sobre a representação concreta do estado. Então, realmente se trata de mensagens, a ligação tardia é uma implementação de mensagens e o encapsulamento é uma conseqüência disso.
Mais tarde, ele esclareceu que " a grande idéia é ' enviar mensagens' " e lamenta tê-la chamado de "orientado a objetos" em vez de "orientado a mensagens", porque o termo "orientado a objetos" coloca o foco na coisa sem importância (objetos ) e distrai o que é realmente importante (mensagens):
Apenas um lembrete gentil de que eu me esforcei no último OOPSLA para tentar lembrar a todos que o Smalltalk não é apenas NÃO sua sintaxe ou a biblioteca de classes, nem mesmo sobre aulas. Sinto muito que, há muito tempo, cunhei o termo "objetos" para este tópico porque leva muitas pessoas a se concentrarem na idéia menor.
A grande idéia é "mensagens" - é disso que trata o kernal do Smalltalk / Squeak (e é algo que nunca foi totalmente concluído em nossa fase do Xerox PARC). Os japoneses têm uma pequena palavra - ma - para "o que está no meio" - talvez o equivalente em inglês mais próximo seja "intersticial". A chave para criar sistemas grandes e cultiváveis é muito mais para projetar como seus módulos se comunicam do que quais devem ser suas propriedades e comportamentos internos. Pense na Internet - para viver, ela (a) precisa permitir muitos tipos diferentes de idéias e realizações que estão além de qualquer padrão único e (b) permitir graus variados de interoperabilidade segura entre essas idéias.
(É claro que hoje em dia a maioria das pessoas nem se concentra nos objetos, mas nas classes, o que é ainda mais errado.)
As mensagens são fundamentais para o OO, tanto como metáfora quanto como mecanismo.
Se você envia uma mensagem a alguém, não sabe o que ela faz. A única coisa que você pode observar é a resposta deles. Você não sabe se eles próprios processaram a mensagem (por exemplo, se o objeto possui um método), se encaminharam a mensagem para outra pessoa (delegação / proxy), se eles a entenderam. É disso que se trata o encapsulamento, do OO. Você não pode nem distinguir um proxy do real, desde que ele responda como você espera.
Um termo mais "moderno" para "sistema de mensagens" é "envio dinâmico de método" ou "chamada virtual de método", mas que perde a metáfora e se concentra no mecanismo.
Pontos semelhantes também são apresentados em On Understanding Data Abstraction, revisitado por William R. Cook e também em sua Proposta de definições modernas e simplificadas de "Objeto" e "Objeto Orientado" .
O envio dinâmico de operações é a característica essencial dos objetos. Isso significa que a operação a ser invocada é uma propriedade dinâmica do próprio objeto. As operações não podem ser identificadas estaticamente e, geralmente, não há como exatamente qual operação será executada em resposta a uma determinada solicitação, exceto executando-a. É exatamente igual às funções de primeira classe, sempre despachadas dinamicamente.
No Smalltalk-72, não havia nenhum objeto! Havia apenas fluxos de mensagens que foram analisados, reescritos e redirecionados. Primeiro vieram os métodos (maneiras padrão de analisar e redirecionar os fluxos de mensagens), depois vieram os objetos (agrupamentos de métodos que compartilham algum estado privado). A herança veio muito mais tarde, e as classes foram introduzidas apenas como uma maneira de apoiar a herança. Se o grupo de pesquisa de Kay já soubesse sobre protótipos, eles provavelmente nunca teriam introduzido aulas em primeiro lugar.
Todo programador deve ler Sobre a compreensão da abstração de dados, revisitada . Explica em detalhes qual é exatamente a diferença entre Objetos e Tipos de Dados Abstratos. Ele dá exemplos usando Java, e que é extremamente relevante para esta pergunta, porque em ambos os exemplos ADT e os exemplos de objetos que ele usa herança, encapsulamento e polimorfismo, mas somente um é orientada a objetos dos exemplos! Em outras palavras: você pode ter herança, encapsulamento e polimorfismo, pode até ter os três ao mesmo tempo e ainda não ter OO.
Por outro lado, você pode ter OO sem herança. Como sugeri acima: as versões originais do Smalltalk (a linguagem projetada por Alan Kay, o inventor do termo "Programação Orientada a Objetos") não tinham herança.
Por fim, mas certamente não menos importante, o Tratado de Orlando discute a delegação como uma alternativa à herança e como diferentes formas de delegação e herança levam a diferentes pontos de design dentro do espaço de design das linguagens orientadas a objetos. (Observe que, mesmo em linguagens que suportam herança, como Java, as pessoas são ensinadas a evitá-la, indicando novamente que não é necessário para o OO).