¿Se implementa STL con OO?

8

Hay varios patrones de diseño como Adaptador, Iterador implementado en STL.

¿Eso significa que STL se implementa con conceptos OO?
¿Cuál es la relación entre OO y las partes de plantilla de C ++?

Aprendí que la función de miembro virtual que justifica el OO está en contradicción con la plantilla, ¿es esto correcto?

upton
fuente
44
El diseñador de la STL es famoso anti-OO. en.wikipedia.org/wiki/Alexander_Stepanov#Criticism_of_OOP
stonemetal

Respuestas:

11

Primero, "STL" no es un término oficial, es el nombre de la biblioteca propuesta para incluir en la Biblioteca Estándar de C ++ cuando no había contenedores. Proporciona esencialmente plantillas de contenedor y algoritmos.

Ahora, estas plantillas de contenedor y algoritmos son ... plantillas, por lo que producen tipos según sea necesario. No se basan en la herencia desde el punto de vista del usuario.

Sin embargo, la biblioteca estándar especifica esencialmente la interfaz de la biblioteca, no la implementación. Muchas implementaciones de STL utilizarán un poco de orientación a objetos en su implementación, pero como usuario no lo verá si no se sumerge en el código fuente de sus implementaciones (que deben exponerse ya que es esencialmente un código de plantilla).

Aprendí que la función de miembro virtual que justifica el OO está en contradicción con la plantilla, ¿es esto correcto?

No, son conceptos ortogonales que proporcionan conjuntos muy diferentes de ventajas y desventajas. De hecho, en C ++, una de las principales ventajas de usar dicho lenguaje es que tiene ambos disponibles y el uso de uno no cancela el uso del otro. Incluso es una gran ventaja. Por ejemplo, uno de los modismos más interesantes en C ++ es CRTP que usa tanto plantillas como herencia. La idea es que la parte de herencia le permite extender varios tipos con un comportamiento y datos comunes, como una clase base; mientras que la parte de la plantilla se asegura de generar clases base específicas para cada niño, haciendo imposible tener un puntero a todas las clases usando la clase CRTP como base. Esto es extremadamente útil y no permite jugar con la herencia donde no debería haberla.

También he implementado sistemas de distribución de eventos muy genéricos que no conocían los tipos de eventos ni los tipos de escucha, pero combinaron código interno dinámico y estático que juntos permitieron generar los tipos internos correctos correspondientes a los tipos de tiempo de ejecución correctos.

Y ese es el punto: no siempre se necesita "orientación a objetos". De hecho, la mayoría de las veces no lo necesita en absoluto, necesita definir algunos tipos y usarlos directamente como parte diferente de algún tipo de motor abstracto (composición). No siempre necesita un código genérico, también conocido como plantillas. A veces lo necesita para generalizar una función que se aplica a varios tipos no relacionados. Cuando están relacionados, puede usar su clase base y no necesitar plantillas.

Tienen diferentes ventajas y costos completamente diferentes, por lo que son buenos para combinar para resolver problemas complejos.

STL es un buen ejemplo de un problema en el que la mayor parte se trata de proporcionar tipos (contenedores) y funciones (algoritmos) que están relacionados con un tipo determinado en lugar de una jerarquía de objetos de tiempo de ejecución. En la biblioteca estándar, los flujos se hacen de una manera típica de la orientación a objetos: es una jerarquía de clases de flujo que hace cosas diferentes de una manera que permite definir una clase de flujo secundario que combina diferentes comportamientos / capacidades. Allí, la orientación a objetos es útil, incluso si algunas personas prefieren que se parezca más al STL (no soy un especialista en el tema).

Entonces, piense en ellas como herramientas muy diferentes, como un destornillador y un martillo. C ++ no te deja pensar con solo una herramienta en mente.

Klaim
fuente
8

En realidad, el STL introdujo el paradigma de programación genérica en la corriente principal.

Cuando me enseñaron el paradigma de Programación Orientada a Objetos (por algún profesor) hace 15 años, me enseñaron que los tres pilares cruciales son la encapsulación, la herencia y el polimorfismo (hoy este último probablemente debería calificarse como polimorfismo de tiempo de ejecución ), mientras que Wikipedia actualmente enumera la abstracción de datos, la encapsulación, la mensajería, la modularidad, el polimorfismo y la herencia como características definitorias de OOP. Por supuesto, el STL usa algunos de ellos, como la encapsulación, pero luego también usa funciones, que son una característica del paradigma de Programación Estructurada . Sin embargo, nadie diría que el STL es Programación Estructurada .

Tenga en cuenta que una de las características más potentes de C ++ es el hecho de que admite muchos paradigmas de programación (Estructurado, Orientado a objetos, Genérico, Programación funcional y otros) y que brilla más donde se mezclan y mezclan.

sbi
fuente
7

Para citar a Alexander Stepanov de su entrevista STLPort :

STL no está orientado a objetos. Creo que la orientación a objetos es casi tan engañosa como la Inteligencia Artificial. Todavía tengo que ver un código interesante que proviene de estas personas OO. [...] OOP me parece filosóficamente poco sólido. Afirma que todo es un objeto. Incluso si es cierto, no es muy interesante: decir que todo es un objeto no dice nada en absoluto. Me parece que la OOP es metodológicamente incorrecta.

Dicho esto, se podría hacer una implementación individual utilizando la herencia y el polimorfismo en algunos lugares. Solo por ejemplo, he visto una implementación en la que iteratorse derivó const_iteratorpara admitir la conversión implícita de iteratora const_iterator. Sin embargo, la derivación no es característica o requerida por el diseño.

En pocas palabras: si bien puede / podría usar código orientado a objetos para implementar algunas partes de la STL, el diseño de la propia STL no está (enfáticamente) orientado a objetos.

Jerry Coffin
fuente
3

No, diría que el STL no es particularmente OO, en todo caso, se asigna más a un estilo de programación funcional. En particular:

  • Los algoritmos std :: son funciones libres, no métodos
  • a menudo toman objetos de función así:. son funciones de orden superior
  • operan en cualquier contenedor
  • std :: transform es un mapa, las funciones X_if son filtros, std :: acumular es plegar / reducir

Del mismo modo, puede argumentar que los contenedores son mónadas

  • la creación de instancias de plantilla es una construcción tipo
  • las secuencias al menos tienen constructores de unidades, por ejemplo vector<string>(1,"Foo")
  • fmap es std :: transform
  • Bind y / o Join son implementables (aunque no se proporcionan de fábrica)
  • cualquier implementación razonable de bind / join cumpliría con las leyes de mónada

Para sus otras preguntas, las partes OO y las partes de plantilla de C ++ están separadas y las funciones virtuales no impiden tener plantillas. En el caso de STL, el diseño simplemente no elige usar funciones virtuales.

jk.
fuente
Las funciones libres frente a los métodos son en gran medida una distinción sintáctica, y solo porque sean funcionales no significa que no estén orientadas a objetos, por el contrario.
Konrad Rudolph el
Además, los algoritmos pueden ser funcionales, pero no hay razón para creer que std::vector<int>no esté orientado a objetos.
DeadMG
3

Depende de a quién le pida una definición de OOP, porque OOP es un término notoriamente mal definido y no hay un buen consenso sobre qué constituye OOP y qué no.

Desde la perspectiva de una persona Java, la respuesta es probablemente "no", ya que la biblioteca de algoritmos y contenedores de C ++ no se ocupa del polimorfismo en tiempo de ejecución, no usa la herencia de clases y porque la sintaxis no parece OOP-y.

Por otro lado, pregunte a una persona de programación funcional y la respuesta puede ser "sí".

Así es como Wikipedia define OOP:

La programación orientada a objetos (OOP) es un paradigma de programación que utiliza "objetos" (estructuras de datos que consisten en campos y métodos de datos junto con sus interacciones) para diseñar aplicaciones y programas informáticos. Las técnicas de programación pueden incluir características tales como abstracción de datos, encapsulación, mensajería, modularidad, polimorfismo y herencia. Muchos lenguajes de programación modernos ahora admiten OOP, al menos como una opción.

Todos estos se realizan, o se ayudan, en la biblioteca estándar de C ++, y en particular en la parte que trata con contenedores y algoritmos. En particular, los algoritmos fortalecen la encapsulación y la abstracción (y, por lo tanto, la modularidad) y son polimorfos mediante el uso de plantillas.

Konrad Rudolph
fuente
Excepto que debe usar la herencia con esos contenedores, que es una de las principales características de OOP.
sbi
1
@sbi Considero que la herencia es un arenque rojo. De lo que se trata realmente la OOP es la abstracción y la reutilización del código, que son facilitados por la herencia. El STL proporciona ambos. Pero solo para satisfacer la definición de Wikipedia al pie de la letra, los contenedores STL se implementan realmente por herencia (aunque eso es, por supuesto, un detalle de implementación).
Konrad Rudolph el
La herencia era una característica principal: antes de las plantillas. Ahora no creo que haya nada más esencial sobre el uso de la herencia para implementar una abstracción que el uso de plantillas para implementar esa abstracción.
DeadMG
Si se habla de herencia en términos generales, y no en la forma en que se define en la sintaxis del lenguaje C ++, se puede argumentar que el vector <int> se hereda del vector de clase base abstracto. A través de la sobrecarga de functores y operadores, logra un polimorfismo específico para el tipo int.
@Lundin True, pero eso es simplemente abstracción de una interfaz. Que es lo que hace la herencia también, y por eso creo que la herencia debería ser menospreciada.
Konrad Rudolph el
1

En mi opinión, STL trata más sobre algoritmos sobre contenedores iterables que OO.

Define una interfaz común (el iterador) que se implementará para utilizar los algoritmos.

Los iteradores de C / C ++ se denominan enumerador / enumerable en Java y C #

Quizás STL está más orientado a aspectos que OO.

k3b
fuente
1

Aprendí esa función de miembro virtual que justifica el OO

¿Dónde demonios escuchaste eso?

Los principios cruciales de la orientación a objetos son la encapsulación y la abstracción. virtuallas funciones son solo un medio por el cual se logra eso. No son necesarios para la orientación real de los objetos. De hecho, una plantilla es un medio perfectamente adecuado. Puede que no sea herencia, pero sigue siendo una especie de polimorfismo. Y algunas clases no requieren ninguno.

Los contenedores de la biblioteca estándar están absolutamente orientados a objetos. Encapsulan todos los detalles innecesarios de la interfaz y abstraen la implementación al máximo que sea razonablemente posible.

DeadMG
fuente
Cuando me enseñaron "OO" hace 15 años, me enseñaron que los tres pilares cruciales son la encapsulación, la herencia y el polimorfismo.
sbi
La herencia y el polimorfismo son solo un medio para los objetivos finales: encapsulación y abstracción. Sin mencionar que si bien las plantillas no usan herencia, son polimórficas.
DeadMG
Bueno, se enseña comúnmente, como dijo sbi. Sin embargo, estoy de acuerdo contigo en que es en gran medida un arenque rojo.
Konrad Rudolph el
-1

La implementación de OOP, por sí sola, no significa nada hasta que no defina lo que quiere decir con "objeto". Si los objetos son valores (no entidades, como la mayoría de los llamados lenguajes OOP pero C ++ asume), entonces STL es OOP, de lo contrario no.

Asuma este fragmento de código:

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

¿Son ay bdos representaciones de una misma persona viva o solo dos pesonas vivas con el mismo nombre?

¿Cuál es el objeto? a, bO la persona viva (s) que representan?

Además, la herencia de C ++ es un mecanismo de agregación técnica que es diferente de la herencia de objetos (que es una abstracción). Los dos pueden coincidir si impone una determinada disciplina (como los Objetos son accesibles a través de la indirecta y son reemplazables, lo que significa que todos los métodos relevantes son virtuales) de lo contrario pueden apuntar a objetivos diferentes (la herencia de C ++ no es más que una "composición implícita" )

Las plantillas también pueden (a través de la especialización) ofrecer un mecanismo de "sustitución", basado en tipos estáticos en lugar de tipos dinámicos (basados ​​en funciones virtuales) y, en este sentido, si se utiliza una misma disciplina en tiempo de compilación, proporcionar una OOP en tiempo de compilación.

En esencia, ninguno de los esquemas de agregación y despacho de C ++ es por sí solo OOP o justifica OOP. También pueden hacer otras cosas. OOP es una metodología abstracta para describir y relacionar objetos juntos. Esas relaciones pueden asignarse a herencia y despacho virtual si los tipos de objeto dependen de la ejecución en tiempo de ejecución, o pueden asignarse a la especialización de plantilla y las conversiones implícitas si los tipos de objeto pueden definirse durante la compilación. La herencia puede ser solo una de las formas de proporcionar una conversión implícita entre referencias y punteros.

Emilio Garavaglia
fuente
La herencia siempre es también un mecanismo de agregación, no solo en C ++.
Konrad Rudolph el
Tengo que votar a favor aquí. Incluso ignorando los métodos virtuales, la composición tiene serias diferencias con la herencia.
DeadMG
@KonradRudolph: cierto, pero la pregunta es sobre C ++.
Emilio Garavaglia
@DeadMG: tenga en cuenta que el significado del término "composición" fuera de la terminología OOP tiene un significado preciso también en inglés simple. Y la herencia (aparte del método virtual) no es más que "componer con un miembro sin nombre". Entiendo perfectamente que a los integrantes de OOP no les gustan estos hechos, pero C ++ no es solo un lenguaje y herencia de OOP, así como la composición de la clase, no son solo servicios de OOP "es un" y "tiene una" relación. ...
Emilio Garavaglia
... Hay una diferencia entre la terminología OOP y la terminología C ++. En los días en que C ++ no tenía otro soporte de paradigma que la herencia y los métodos virtuales (sin plantillas y sin lambdas), la terminología podría haberse confundido deliberadamente y utilizado una en lugar de otra, pero hoy en día reduce la herencia de OOP para implementar solo la OOP El principio de sustitución es castrar deliberadamente el lenguaje.
Emilio Garavaglia