Qual é o benefício da programação orientada a objetos sobre programação procedural?

76

Estou tentando entender a diferença entre linguagens procedurais como C e linguagens orientadas a objetos como C ++. Eu nunca usei C ++, mas tenho discutido com meus amigos como diferenciar os dois.

Já me disseram que o C ++ tem conceitos orientados a objetos, assim como modos público e privado para definição de variáveis: coisas que C não possui. Eu nunca tive que usá-los para desenvolver programas no Visual Basic.NET: quais são os benefícios disso?

Também me disseram que se uma variável é pública, ela pode ser acessada em qualquer lugar, mas não está claro como isso é diferente de uma variável global em uma linguagem como C. Também não está claro como uma variável privada difere de uma variável. variável local.

Outra coisa que eu ouvi é que, por razões de segurança, se uma função precisa ser acessada, ela deve ser herdada primeiro. O caso de uso é que um administrador deve ter tanto direito quanto necessário e não tudo, mas parece que um condicional também funcionaria:

if ( login == "admin") {
    // invoke the function
}

Por que isso não é ideal?

Dado que parece haver uma maneira processual de fazer tudo orientado a objetos, por que eu deveria me preocupar com programação orientada a objetos?

    
por niko 16.11.2011 / 06:20
fonte

12 respostas

133

Todas as respostas até agora se concentraram no tópico de sua pergunta, como indicado, que é "qual é a diferença entre c e c ++". Na realidade, parece que você sabe qual é a diferença, você simplesmente não entende por que você precisaria dessa diferença. Então, outras respostas tentaram explicar OO e encapsulamento.

Eu queria falar com mais uma resposta, porque, com base nos detalhes da sua pergunta, acredito que você precisa dar vários passos para trás.

Você não entende o propósito de C ++ ou OO, porque para você, parece que seu aplicativo simplesmente precisa armazenar dados. Esses dados são armazenados em variáveis. "Por que eu iria querer tornar uma variável inacessível? Agora não posso mais acessá-la! Ao tornar tudo público, ou melhor ainda, global, posso ler dados de qualquer lugar e não há problemas." - E você está certo, com base na escala dos projetos que você está escrevendo atualmente, provavelmente não há muitos problemas (ou existem, mas você ainda não se deu conta deles ainda).

Eu acho que a questão fundamental que você realmente precisa ter respondido é: "Por que eu iria querer esconder dados? Se eu fizer isso, não posso trabalhar com isso!" E é por isso que:

Digamos que você inicie um novo projeto, abra seu editor de texto e comece a escrever funções. Toda vez que você precisa armazenar algo (para lembrá-lo para mais tarde), você cria uma variável. Para tornar as coisas mais simples, você torna suas variáveis globais. Sua primeira versão do seu aplicativo é excelente. Agora você começa a adicionar mais recursos. Você tem mais funções, certos dados armazenados antes precisam ser lidos do novo código. Outras variáveis precisam ser modificadas. Você continua escrevendo mais funções. O que você pode ter notado (ou, se não, você notará no futuro) é, à medida que seu código fica maior, você demora mais e mais para adicionar o próximo recurso. E à medida que seu código fica maior, fica cada vez mais difícil adicionar recursos sem quebrar algo que costumava funcionar. Por quê? Porque você precisa lembrar o que todas suas variáveis globais estão armazenando e você precisa lembrar onde todas delas estão sendo modificadas. E você precisa lembrar qual função é válida para chamar qual ordem exata e se você as chamar em uma ordem diferente , poderá receber erros porque suas variáveis globais não são bastante válido ainda. Você já se deparou com isso?

Qual é o tamanho dos seus projetos típicos (linhas de código)? Agora imaginando um projeto de 5000 a 50000 vezes maior que o seu. Além disso, existem várias pessoas trabalhando nele. Como todos da equipe podem lembrar (ou mesmo estar cientes) do que todas essas variáveis estão fazendo?

O que eu descrevi acima é um exemplo de código perfeitamente acoplado. E desde o início dos tempos (assumindo que o tempo começou em 1º de janeiro de 1970), a espécie humana tem procurado maneiras de evitar esses problemas. A maneira de evitá-los é dividindo seu código em sistemas, subsistemas e componentes e limitando quantas funções têm acesso a qualquer parte dos dados. Se eu tiver 5 inteiros e uma string que represente algum tipo de estado, seria mais fácil para mim trabalhar com este estado se apenas 5 funções configurassem / conseguissem os valores? ou se 100 funções configuradas / obtêm esses mesmos valores? Mesmo sem as linguagens OO (ou seja, C), as pessoas têm trabalhado duro para isolar dados de outros dados e criar limites de separação limpos entre diferentes partes do código. Quando o projeto chega a um certo tamanho, a facilidade de programação não se torna "eu posso acessar a variável X da função Y", mas "como eu me certifico SOMENTE de funções A, B, C e ninguém mais está tocando na variável X".

É por isso que conceitos OO foram introduzidos e é por isso que eles são tão poderosos. Eles permitem que você esconda seus dados de si mesmo e você deseja que faça isso de propósito, porque quanto menos código vir esses dados, menor a chance de que, quando você adicionar o próximo recurso, você quebrar alguma coisa. Este é o objetivo principal dos conceitos de encapsulamento e programação OO. Eles permitem que você quebre nossos sistemas / subsistemas em caixas ainda mais granulares, a um ponto em que, não importa quão grande seja o projeto, um determinado conjunto de variáveis só pode ser acessado por 50-200 linhas de código e pronto! Obviamente, há muito mais para programação OO, mas, em essência, é por isso que o C ++ oferece opções para declarar dados / funções como privadas, protegidas ou públicas.

A segunda maior ideia em OO é o conceito de camadas de abstração. Embora as linguagens procedurais também possam ter abstrações, em C, um programador deve fazer um esforço consciente para criar essas camadas, mas em C ++, quando você declara uma classe, cria automaticamente uma camada de abstração (ainda depende de você irá adicionar ou remover valor). Você deve ler / pesquisar mais sobre as camadas de abstração e, se tiver mais perguntas, tenho certeza de que este fórum terá muito prazer em respondê-las também.

    
por 16.11.2011 / 09:05
fonte
10

Hmm ... talvez seja melhor fazer backup e tentar dar uma idéia da intenção básica da programação orientada a objetos. Grande parte da intenção da programação orientada a objetos é permitir a criação de tipos de dados abstratos. Para um exemplo muito simples com o qual você está, sem dúvida, familiarizado, considere uma string. Uma string normalmente terá um buffer para conter o conteúdo da string, algumas funções que podem operar na string (pesquisar nele, acessar partes dela, criar substrings, etc.). Ele também (pelo menos tipicamente) tem algo a rastreie o comprimento (atual) da string, e (provavelmente) o tamanho do buffer, então se (por exemplo) você aumentar o tamanho da string de 1 para 1000000, ele saberá quando precisar de mais memória para armazenar o tamanho maior. conteúdo.

Essas variáveis (o buffer, o comprimento atual e o tamanho do buffer) são privadas para a string em si, mas não são locais para uma função específica. Cada string tem conteúdo de algum tamanho específico, então precisamos rastrear esse conteúdo / tamanho para aquela string. Por outro lado, a mesma função (por exemplo, para extrair uma substring) pode operar em muitas strings diferentes em momentos diferentes, de modo que os dados não podem ser locais para a função individual.

Como tal, acabamos com alguns dados que são privados para a cadeia de caracteres, por isso é apenas (diretamente) acessível para funções de string. O mundo exterior pode obter o comprimento da string usando uma função de string, mas não precisa saber nada sobre os componentes internos da string para obtê-la. Da mesma forma, ele pode modificar a string - mas, novamente, ela faz isso por meio das funções de string, e apenas modifica diretamente essas variáveis locais para o objeto string.

No que diz respeito à segurança, eu notaria que, embora isso seja razoável como uma analogia, não é como as coisas realmente funcionam. Em particular, o acesso em C ++ é especificamente não destinado a atender ao mesmo tipo de requisitos que o acesso em um sistema operacional. Supõe-se que um sistema operacional imponha as restrições para que (por exemplo) um usuário normal não possa fazer as coisas reservadas para um administrador. Por outro lado, o controle de acesso em C ++ destina-se apenas a evitar acidentes . Por design, quem quiser pode contorná-las facilmente. Eles estão na mesma ordem que marcar um arquivo como somente leitura para que você não o exclua acidentalmente. Se você decidir excluir o arquivo, é trivial alterá-lo de somente leitura para leitura / gravação; Tudo que você definiu para somente leitura faz com que você, pelo menos, pense sobre isso por um segundo e decida para apagar o arquivo para que ele não seja apagado acidentalmente apenas pressionando a tecla errada na hora errada. .

    
por 16.11.2011 / 07:17
fonte
6

OOP versus C não é realmente sobre nenhuma das coisas que você discutiu. É basicamente sobre o código de empacotamento em áreas que não podem / não podem, não intencionalmente (ou às vezes intencionalmente) se afetarem mutuamente.

C permite basicamente executar qualquer função de qualquer lugar. OOP evita isso agrupando métodos em classes e permitindo apenas que você use os métodos referenciando a classe que os contém. Assim, uma vantagem potencialmente grande da OOP é que você tem muito mais probabilidade de ter um arranjo de código melhor sem muita experiência para lhe dizer que deveria.

    
por 16.11.2011 / 07:18
fonte
4

Uma classe bem escrita deve ser uma pequena "ilha de confiança": você pode usá-la e assumir que ela faz "a coisa certa" e que ela protege você de armadilhas comuns. Isso torna uma boa classe um bloco de construção, que é muito mais reutilizável como um monte de funções e variáveis, que podem funcionar bem, mas mostrar a você todas as suas feias entranhas e forçá-lo a entender como elas funcionam juntas, como elas precisam ser inicializadas etc. Uma boa classe deve ser como um plugue USB, enquanto a solução processual é como um monte de fios, chips, estanho e um pouco de solda.

Um ponto que não foi discutido em profundidade é o aspecto de interface / implementação. Uma interface descreve o comportamento, mas não a realização. Portanto, uma interface de lista descreve o conceito de uma lista e seu comportamento: você esperaria coisas como adicionar, remover e dimensionar métodos. Agora existem várias maneiras diferentes de implementar essa lista, por exemplo, como uma lista vinculada ou usando um buffer de matriz. O poder da programação OO é que, usando uma interface, você pode raciocinar sobre o comportamento sem saber sobre a implementação. Acessar variáveis internas ou métodos destruiria essa abstração, você não poderia substituir uma implementação de lista por outra e não poderia melhorar uma implementação existente sem tocar no código usando a classe. Essa é uma das principais razões pelas quais variáveis e métodos privados são necessários: Para proteger os detalhes internos da implementação, a abstração permanece intacta.

OO vai ainda mais longe: por exemplo. para bibliotecas, você pode definir uma interface para coisas que ainda não existem , e escrever código que funcione com essa interface. Os usuários podem gravar classes implementando a interface e usar os serviços fornecidos pela biblioteca. Isso permite um grau de flexibilidade que não é possível com a programação processual.

    
por 18.11.2011 / 10:01
fonte
3

Existe uma maneira de fazer tudo com uma máquina de Turing, ou no mínimo em uma linguagem de montagem para o código de máquina que um programa C ou C ++ eventualmente compilará.

Portanto, a diferença não é sobre o que o código pode fazer, mas sobre o que as pessoas podem fazer.

As pessoas cometem erros. Muitos.

OOP introduz um paradigma e uma sintaxe que ajuda a reduzir o tamanho e a densidade de probabilidade do espaço de possíveis erros de codificação humanos. Às vezes, tornando o erro ilegal para uma determinada classe de objeto de dados (como se não fosse um método declarado para esse objeto). Às vezes, tornando o erro mais detalhado, ou estilisticamente estranho, comparado ao uso canônico da linguagem. Às vezes, exigindo uma interface com muito menos possíveis usos inconsistentes ou emaranhados (públicos versus privados). etc.

Quanto maior o projeto, maior a probabilidade de erros. Que um novo codificador não pode ser exposto se experimentado apenas com pequenos programas. Assim, a perplexidade potencial do motivo da OOP é valiosa.

    
por 16.11.2011 / 20:22
fonte
2

Sua pergunta parece mais sobre o propósito da OOP, em vez da diferença. O conceito no seu post é encapsulamento; e o encapsulamento existe para apoiar a CHANGE. Quando outras classes estão acessando seus internos, torna-se difícil modificá-las sem quebrá-las. Em OOP você fornece uma interface (membros públicos) através da qual você permite que outras classes interajam com as suas, e você esconde seus componentes internos para que eles possam ser alterados com segurança.

    
por 16.11.2011 / 08:26
fonte
2

No matter where I read private variables cannot be accessed whereas public variables can be then why not make public as global and private as local whats the difference? whats the real use of public and private ? please dont say it can be used by everyone, I suppose why not we use some conditions and make the calls ?

Espero que você nunca queira mais de uma string em seu aplicativo. Também espero que suas variáveis locais persistam entre as chamadas de função. Essas coisas podem ser as mesmas em termos de acessibilidade, mas em termos de tempo de vida e outros usos? Eles não são absolutamente os mesmos.

    
por 16.11.2011 / 08:30
fonte
1

Como muitos disseram, qualquer programa, uma vez compilado, é transformado em um código binário e, como uma string binária pode ser usada para representar um inteiro, qualquer programa é eventualmente apenas um número. No entanto definir o número que você precisa pode ser bastante difícil e é por isso que as linguagens de programação de alto nível surgiram. Linguagens de programação são apenas modelos do código de montagem que eventualmente produzem. Eu gostaria de explicar-lhe a diferença entre programação procedural e OO por meio deste artigo muito interessante sobre Programação Orientada ao Contexto link

Como você pode ver nesta figura, descrita no artigo, a programação procedural fornece apenas uma dimensão para associar uma unidade computacional a um nome. Aqui, chamadas ou nomes de procedimentos são diretamente mapeados para implementações de procedimentos. Na Figura-a chamada m1 não deixa escolha senão a invocação da única implementação do procedimento m1.

A programação orientada a objetos adiciona outra dimensão para a resolução de nomes àquela da programação procedural. Além do método ou nome do procedimento, o envio de mensagens leva o receptor da mensagem em consideração ao procurar um método. Na Figura-b, vemos duas implementações do método m1. A seleção do método apropriado não depende apenas do nome da mensagem m1, mas também do receptor da mensagem atual, aqui Ry.

Isso realmente permite o encapsulamento e a modularização.

A figura-c é finalmente sobre programação orientada a assuntos estende o envio de métodos orientados a objetos por outra dimensão.

Espero que isso tenha ajudado você a pensar na OOP de uma perspectiva diferente.

    
por 16.11.2011 / 22:28
fonte
0

(+ 1) Fazer uma pergunta sobre algo que você não entende, é bom, mesmo que pareça bobo.

A diferença é Object & Programação Orientada por Classe. "Plain C", trabalha com dados & funções. "C ++" adiciona conceitos "object & classes", além de vários conceitos secundários relacionados.

No entanto, defendo que os desenvolvedores aprendam "Plain C" antes de "C ++". Ou "Pascal Procedural" antes de "Object Pascal".

Muitos desenvolvedores acham que os alunos devem ensinar apenas uma coisa.

Por exemplo, professores antigos que não recebem O.O. e ensinam apenas "C Estruturado Simples".

Ou professores "hipster" que ensinam apenas O.O., mas não "Plain C", porque "você não precisa disso". Ou ambos, sem se importar com a ordem de ensino.

Eu acho que os alunos devem aprender tanto o "Structured Plain C" quanto o "Object Oriented C (C ++)". Com "Plain C", primeiro e "C ++", mais tarde.

No mundo real, você precisa aprender os dois paradigmas (além de outros paradigmas, como "funcional").

Pensar em programas estruturados como um "objeto" grande e único pode ajudar.

Você também deve colocar ênfase nos namespaces ("módulos"), em ambos os idiomas, muitos professores simplesmente ignoram, mas é importante.

    
por 16.11.2011 / 18:51
fonte
0

Em uma palavra, gerenciamento de projetos. O que quero dizer é que o C ++ me ajuda a impor regras de como meu código é usado por outras pessoas. Trabalhando em um projeto de 5,5 milhões de linhas, acho muito útil a programação orientada a objetos. Outra vantagem é o compilador que faz com que eu (e todos os outros) sigam certas regras e capturem pequenos erros em tempo de compilação. Todas as vantagens teóricas estão lá também, mas eu só queria me concentrar nas coisas práticas do dia a dia. Afinal tudo compila em código de máquina.

    
por 18.11.2011 / 07:34
fonte
-1

Programação Orientada a Objetos é Programação Procedural, com caixas.

No PP, você tem uma caixa, um estado, que se torna incrivelmente grande à medida que o projeto cresce, fazendo com que os efeitos colaterais apareçam toda vez que você esquece um pouquinho desse grande estado.

No OO, você tem muitas caixas, muitos estados e, à medida que o projeto cresce, as caixas crescem um pouco e o número de caixas cresce muito.

Continua a ser mais fácil olhar para caixas menores, fácil ter a ilusão de uma imagem inteira, mas na verdade quase impossível, já que observar classes e interfaces oculta os detalhes da implementação que podem ter importantes ramificações.

Na programação funcional, você tem muitas caixas de funções e decide que cada função tem uma entrada (parâmetros) e uma saída (retorna), com estritamente nenhum outro acesso ao contexto externo.

Como não há estado nem efeitos colaterais (por design), você pode analisar com segurança qualquer função separadamente do todo e saber 100% como ela se comportará em qualquer circunstância.

Como você é um código de boxe por unidades lógicas que representam ações, também é possível ter apenas uma caixa por ação típica.

Isso reduzirá o código de qualquer projeto de grande escala por um fator enorme em comparação com a OOP, o que promove a ocultação de múltiplas funções analógicas por toda a base de código em classes diferentes.

Isso também irá vencer o PP por muito tempo, porque você pode aumentar o projeto por muito mais tempo, já que não há mais o estado XXXXXXXL para acompanhar.

Em resumo, o PP é provavelmente a forma mais simples de abordar um programa simples e o FP é provavelmente a maneira mais simples de abordar um programa complexo.

Se você considerar o objetivo de unificar todas as bases de código e melhorar a reutilização de código, o FP sempre deve ser usado, pois é o único paradigma que faz sentido em uma escala muito grande, bem como o único paradigma que possui 100% de reutilização. (você pode simplesmente copiar e colar uma função e usá-la em outro lugar, sem nenhuma sobrecarga).

E você obtém testes de unidade 100% confiáveis gratuitamente.

E você não precisa escrever "private static final of_doom genius awesome string_1".

E você recebe paralelismo de graça.

    
por 28.09.2013 / 09:22
fonte
-3

A diferença simples de uma sentença é que C ++ é C com Classes. (embora seja muito mais agora) Não sei por que você não quer aprender as diferenças entre duas lendo uma ótimo artigo sobre C ++ na Wikipedia ..... Este artigo irá ajudá-lo bastante: - C ++ (Wikipedia)

Também pesquisando sobre o assunto ajudará. Pedir a pessoas aleatórias para explicar isso pode ser complicado. IMHO, entende-se melhor lendo do que perguntando a alguém

    
por 16.11.2011 / 06:59
fonte