STL é implementado com OO?


8

Existem vários padrões de design como o Adapter, Iterator implementado no STL.

Isso significa que o STL é implementado com os conceitos de OO?
Qual é a relação entre OO e partes do modelo do C ++?

Aprendi que a função de membro virtual que justifica o OO está em contradição com o modelo, isso está correto?


4
O designer do STL é famoso por anti-OO. en.wikipedia.org/wiki/Alexander_Stepanov#Criticism_of_OOP
stonemetal

Respostas:


11

Primeiro, "STL" não é um termo oficial, é o nome da biblioteca proposta para inclusão na Biblioteca Padrão C ++ quando não havia contêineres. Ele fornece essencialmente modelos de contêiner e algoritmos.

Agora, esses modelos de contêiner e algoritmos são ... modelos para que eles produzam tipos conforme necessário. Eles não confiam na herança do ponto de vista do usuário.

No entanto, a biblioteca padrão especifica essencialmente a interface da biblioteca, não a implementação. Muitas implementações de STL usarão um pouco de orientação a objetos em sua implementação, mas como usuário você não a verá se não mergulhar no código-fonte das implementações (que precisa ser exposto, pois é essencialmente o código do modelo).

Aprendi que a função de membro virtual que justifica o OO está em contradição com o modelo, isso está correto?

Não, são conceitos ortogonais que fornecem conjuntos muito diferentes de vantagens e contras. De fato, em C ++, uma das principais vantagens de usar essa linguagem é que você tem disponível e o uso de um não cancela o uso do outro. É até uma vantagem muito grande. Por exemplo, um dos idiomas mais interessantes em C ++ é o CRTP, que usa modelos e herança. A ideia é que a parte de herança permita estender vários tipos com um comportamento e dados comuns, como uma classe base; enquanto a parte do modelo garante a geração de classes base específicas para cada filho, impossibilitando um ponteiro para todas as classes usando a classe CRTP como base. Isso é extremamente útil e não permite mexer com a herança onde não deveria haver.

Também implementei sistemas muito genéricos de despacho de eventos que não conheciam tipos de eventos ou tipos de ouvintes, mas combinamos código dinâmico e estático internamente que juntos permitiam gerar os tipos internos corretos correspondentes aos tipos corretos de tempo de execução.

E esse é o ponto: você nem sempre precisa de "orientação a objetos". De fato, na maioria das vezes você não precisa disso, precisa definir alguns tipos e usá-los diretamente como parte diferente de algum tipo de mecanismo abstrato (composição). Você nem sempre precisa de código genérico, também conhecido como modelos. Às vezes, é necessário generalizar uma função para aplicar a vários tipos não relacionados. Quando eles estão relacionados, você pode usar a classe base e não precisa de modelos.

Eles têm vantagens diferentes e custos completamente diferentes, portanto, são bons para combinar para resolver problemas complexos.

STL é um bom exemplo de um problema em que a maioria se refere ao fornecimento de tipos (contêineres) e funções (algoritmos) relacionados a um determinado tipo, em vez de uma hierarquia de objetos de tempo de execução. Na biblioteca padrão, os fluxos são feitos de uma maneira típica da orientação a objetos: é uma hierarquia de classes de fluxo que faz coisas diferentes de uma maneira que permite definir uma classe de sub-fluxo que combina comportamentos / capacidades diferentes. Lá, a orientação a objetos é útil, mesmo que algumas pessoas prefiram que seja mais parecida com a STL (não sou especialista no assunto).

Então, pense nelas como ferramentas muito diferentes, como uma chave de fenda e um martelo. O C ++ não permite que você pense com apenas uma ferramenta em mente.


8

Na verdade, o STL introduziu o paradigma de programação genérica no mainstream.

Quando fui ensinado sobre o paradigma de Programação Orientada a Objetos (por algum professor) há 15 anos, aprendi que os três pilares cruciais são encapsulamento, herança e polimorfismo (hoje esse último provavelmente deve ser qualificado como polimorfismo em tempo de execução ), enquanto a Wikipedia atualmente lista abstração de dados, encapsulamento, sistema de mensagens, modularidade, polimorfismo e herança como características definidoras de POO. Obviamente, o STL usa alguns deles, como encapsulamento, mas também usa funções, que são uma característica do paradigma de Programação Estruturada . No entanto, ninguém argumentaria que o STL é programação estruturada .

Observe que um dos recursos mais fortes do C ++ é o fato de que ele suporta muitos paradigmas de programação (Estruturado, Orientado a Objetos, Genérico, Programação Funcional e outros) e que brilha mais onde você os mistura e combina.


7

Para citar Alexander Stepanov de sua entrevista no STLPort :

STL não é orientado a objetos. Eu acho que a orientação a objetos é quase tão falsa quanto a Inteligência Artificial. Ainda tenho que ver um pedaço interessante de código que vem dessas pessoas OO. [...] acho POO filosoficamente doentio. Alega que tudo é um objeto. Mesmo que seja verdade, não é muito interessante - dizer que tudo é um objeto não está dizendo nada. Acho OOP metodologicamente errado.

Dito isto, uma implementação individual pode ser feita usando herança e polimorfismo em alguns lugares. Apenas por exemplo, eu vi uma implementação na qual iteratorfoi derivada de const_iteratorpara suportar a conversão implícita de iteratorpara const_iterator. A derivação não é , no entanto, característica ou requerida pelo design.

Conclusão: enquanto você pode / pode usar código orientado a objetos para implementar algumas partes do STL, o design do STL em si (enfaticamente) não é orientado a objetos.


3

Não, eu diria que o STL não é particularmente OO, se é que mapeia mais para um estilo de programação funcional. Em particular:

  • Os algoritmos std :: são funções livres, não métodos
  • eles geralmente usam objetos funcionais para:. são funções de ordem superior
  • eles operam em qualquer contêiner
  • std :: transform é map, as funções X_if são filtros, std :: acumulate é fold / reduz

Da mesma forma, você pode argumentar que os contêineres são mônadas

  • instanciação de modelo é uma construção de tipo
  • as sequências têm pelo menos construtores de unidades, por exemplo vector<string>(1,"Foo")
  • fmap é std :: transform
  • bind e / ou join são implementáveis ​​(embora não sejam fornecidos imediatamente)
  • qualquer implementação razoável de ligação / união atenderia às leis da mônada

Para suas outras perguntas, as partes OO e partes do modelo do C ++ são separadas e as funções virtuais não impedem a existência de modelos. No caso do STL, o design simplesmente não escolhe usar funções virtuais.


Funções livres versus métodos é em grande parte uma distinção sintática, e apenas porque são funcionais não significa que não são orientadas a objetos, pelo contrário.
9289 Konrad Rudolph

Além disso, os algoritmos podem ser funcionais, mas não há razão para acreditar que std::vector<int>não seja orientado a objetos.
DeadMG

3

Depende de quem você pede uma definição de POO, porque POO é um termo notoriamente mal definido e não há um bom consenso sobre o que constitui POO e o que não.

Do ponto de vista de uma pessoa Java, a resposta é provavelmente "não", já que a biblioteca de algoritmos e contêineres de C ++ não lida com polimorfismo em tempo de execução, não usa herança de classe e porque a sintaxe não parece OOP-y.

Por outro lado, pergunte a uma pessoa de programação funcional e a resposta pode ser "sim".

Veja como a Wikipedia define OOP:

A programação orientada a objetos (OOP) é ​​um paradigma de programação que usa "objetos" - estruturas de dados que consistem em campos e métodos de dados juntamente com suas interações - para projetar aplicativos e programas de computador. As técnicas de programação podem incluir recursos como abstração de dados, encapsulamento, sistema de mensagens, modularidade, polimorfismo e herança. Muitas linguagens de programação modernas agora suportam OOP, pelo menos como uma opção.

Tudo isso é realizado, ou auxiliado, na biblioteca padrão do C ++ e, em particular, na parte que trata de contêineres e algoritmos. Em particular, os algoritmos fortalecem o encapsulamento e a abstração (e, portanto, a modularidade) e são polimórficos através do uso de modelos.


Exceto que você deve usar a herança com esses contêineres, que é um dos principais recursos do OOP.
S7 de

1
@sbi Considero a herança um arenque vermelho. O que realmente é OOP é abstração e reutilização de código, que são facilitadas pela herança. O STL fornece ambos. Mas apenas para satisfazer a definição da Wikipedia, os contêineres STL são realmente implementados por herança (embora isso seja, obviamente, um detalhe de implementação).
precisa saber é o seguinte

A herança era uma característica principal - antes dos modelos. Agora, acho que não há nada mais essencial em usar herança para implementar uma abstração do que usar modelos para implementar essa abstração.
DeadMG

Se alguém fala de herança em termos gerais, e não da maneira como é definida na sintaxe da linguagem C ++, pode-se argumentar que o vetor <int> é herdado do vetor abstrato da classe base. Através de functores e sobrecarga do operador, ele atinge polimorfismo específico para o tipo int.

@Lundin True, mas isso é simplesmente abstração de uma interface. É o que a herança também faz, e é por isso que acho que a herança deve ser enfatizada.
Konrad Rudolph

1

Na minha opinião, o STL é mais sobre algoritmos sobre contêineres iteráveis ​​do que OO.

Ele define uma interface comum (o iterador) a ser implementada para usar os algoritmos.

Os iteradores C / C ++ são chamados enumerator / enumeratable em Java e C #

Talvez STL seja mais orientado a aspectos que OO.


1

Eu aprendi que a função de membro virtual que justifica o OO

Onde diabos você ouviu isso?

Os princípios cruciais da orientação a objetos são encapsulamento e abstração. virtualfunções são apenas um meio pelo qual isso é alcançado. Eles não são necessários para a orientação real do objeto. De fato, um modelo é um meio perfeitamente adequado. Pode não ser uma herança, mas ainda é um tipo de polimorfismo. E algumas classes não exigem nenhum.

Os contêineres da biblioteca Standard são absolutamente orientados a objetos. Eles encapsulam todos os detalhes desnecessários da interface e abstraem a implementação ao máximo que for razoavelmente possível.


Quando fui ensinado "OO" há 15 anos, aprendi que os três pilares cruciais são encapsulamento, herança e polimorfismo.
SBI

Herança e polimorfismo são apenas um meio para atingir os objetivos finais: encapsulamento e abstração. Sem mencionar que, embora os modelos não usem herança, eles são polimórficos.
DeadMG

Bem, é comumente ensinado, como o sbi disse. Eu concordo com você que é basicamente um arenque vermelho.
Konrad Rudolph

-1

A implementação de OOP, por si só, não significa nada até você não definir o que você quer dizer com "objeto". Se Objetos são valores (não entidades, como a maioria das chamadas linguagens OOP, mas C ++ assume), STL é OOP, caso contrário não.

Suponha este fragmento de código:

Person a("joe");
Person b = a;

Existem ae bduas representações de uma mesma pessoa viva ou apenas dois pesons vivos com o mesmo nome?

Qual é o objeto? a, bOu a pessoa (s) que vivem eles representam?

Além disso, a herança do C ++ é um mecanismo de agregação técnica diferente da herança do Objeto (que é uma abstração). Os dois podem coincidir se você impor uma determinada disciplina (como objetos são acessíveis por meio de indireção e são todos substituíveis - isso significa que todos os métodos relevantes são virtuais), caso contrário, eles podem atingir objetivos diferentes (a herança C ++ nada mais é do que uma "composição implícita" )

Os modelos também podem (via especialização) oferecer mecanismo de "substituição", com base em tipos estáticos, em vez de tipos dinâmicos (com base em funções virtuais) e, nesse sentido, se uma mesma disciplina for usada no tempo de compilação, fornecer um OOP em tempo de compilação.

Em essência, os esquemas de agregação e despacho de C ++ não são, por si só, POO ou justificação de POO. Eles podem fazer outras coisas também. OOP é uma metodologia abstrata para descrever e relacionar objetos juntos. Essas relações podem ser mapeadas para herança e despacho virtual se os tipos de objetos dependerem da execução em tempo de execução ou podem ser mapeadas para especialização de modelos e conversões implícitas se os tipos de objetos puderem ser definidos durante a compilação. A herança pode ser apenas uma das formas de fornecer conversão implícita entre referências e ponteiros.


A herança também é sempre um mecanismo de agregação, não apenas em C ++.
Konrad Rudolph

Eu tenho que votar aqui. Mesmo ignorando os métodos virtuais, a composição tem sérias diferenças na herança.
DeadMG

@ KonradRudolph: true, mas a pergunta é sobre C ++.
Emilio Garavaglia

@DeadMG: observe que o significado do termo "composição" fora da terminologia OOP tem um significado preciso também em inglês comum. E herança (método virtual separado) nada mais é do que "compor com um membro sem nome". Entendo perfeitamente que os integralistas de OOP não gostam desses fatos, mas o C ++ não é apenas uma linguagem e herança de OOP, assim como a composição de classes não estão apenas atendendo a OOP "é um" e "tem" relacionamentos. ...
Emilio Garavaglia

... Há uma diferença entre a terminologia OOP e a terminologia C ++. Nos tempos em que o C ++ não tinha outro suporte de paradigma além de métodos virtuais e de herança (sem tempates e sem lambdas), as duas terminologias poderiam ter sido deliberadamente confusas e usadas uma no lugar da outra, mas hoje em dia a redução da herança de OOP para apenas implementar o OOP princípio de substituição é castrar deliberadamente o idioma.
Emilio Garavaglia
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.