miércoles, 10 de abril de 2019

Herramientas auxiliares de programación estudios de caso

Para programar tanto en C, como en C++, Java o cualquier otro lenguaje de programación, necesitamos contar con aplicaciones o herramientas que nos permitan poner en funcionamiento nuestro programa.

El lenguaje de programación C es compilado, así que en este caso necesitaremos un compilador, que será el encargado de transformar nuestro código fuente en código que la computadora pueda ejecutar.

Además, para facilitar la tarea de los programadores existen los denominados Entorno de desarrollo integrados (IDE). En muchos casos, estos entornos incluyen un compilador, un depurador, y otras herramientas.

Las herramientas a instalar dependerán del sistema operativo utilizado. A continuación se listan algunas posibilidades para el sistema operativo Windows o GNU/Linux, no es imprescindible utilizar estas herramientas en particular, cualquier compilador puede servir.

Windows

Uno de los entornos de desarrollo más conocidos entre los programadores de C sobre Windows, tanto novatos como expertos, es el Bloodshed Dev-C++, que es un entorno libre multiplataforma. Tal entorno de desarrollo fue abandonado y retomado mejorándolo pasando a llamarse WxDev-C++. Otro entorno libre y gratuito es el Code::Blocks. Ambos entornos pueden utilizarse tanto para C como para C++.

También hay otras alternativas privativas como los compiladores de Borland o de Microsoft (Microsoft Visual C++).

GNU/Linux

En los sistemas GNU/Linux, será necesario tener instaladas las herramientas gcc y make y la versión 6 de la glibc con su documentación, que son las que permitirán compilar los programas.

Para escribir y modificar el código, es posible utilizar cualquier editor de texto plano (en lo posible que cuente con resaltado de sintaxis), como son emacs, vim, kate, gedit o geany.

Sin embargo, para quienes son novatos en la programación, es recomendable utilizar un entorno de desarrollo como son el Anjuta DevStudio (para el entorno GNOME) o KDevelop (para el entorno KDE), ya que incluyen facilidades adicionales para la ejecución y solución de problemas.

Los programas mencionados se incluyen dentro de la instalación estándar de la mayoría de las distribuciones actuales de GNU/Linux, de modo que para instalarlos sólo será necesario seguir el procedimiento usual de instalación de aplicaciones para la distribución deseada.

Diseño Orientado A Objetos

El DOO requiere la definición de: una arquitectura multicapa. la especificación de subsistemas que realizan funciones y proveen soporte de infraestructura. Una descripción de objetos (clases). Una descripción de los mecanismos de comunicación.

DISEÑO PARA SISTEMAS ORIENTADOS A OBJETOS

Se divide en 4 capas: – La capa subsistema: contiene una representación de cada uno de los subsistemas, para conseguir sus requisitos definidos por el cliente. – La capa de clases y objetos: contiene la jerarquía de clases, que permite al sistema ser creado usando generalizaciones y con especificaciones mas acertadas.

la capa de mensaje: contiene detalles de diseño, que permite a cada objeto comunicarse son sus colaboradores.

 La capa de responsabilidades: contiene estructuras de datos y diseños algorítmicos, para todos los atributos y operaciones de cada objeto.

La capa fundamental se centra en el diseño de los objetos del dominio. Estos juegan un papel clave, en la construccion de la infraestructura del sistema OO aportando soporte para las actividades, admon de tareas y gestion de datos.

Fichman y Kemerer :

 1. representación de la jerarquía de módulos.
 2. especificación de las definiciones de datos.
 3. especificación de la lógica procedimental.
 4. indicación de secuencias de proceso final - a -final
 5. representación de estados y transiciones de los
 6. definición de clases y jerarquías.
 7. asignación de operaciones a las clases.
 8. definición detallada de operaciones.
 9. especificación de conexiones de mensajes.
10. identificación de servicios exclusivos.

Manipulación de Excepciones como instrumento para el tratamiento de errores

El manejo correcto de errores y excepciones es importante para que el nodo de integración funcione correctamente. Debe considerar cómo y cuándo la extensión definida por el usuario debe manejar errores y excepciones.
El manejo de errores y excepciones de este tema describe factores que debe tener en cuenta cuando desarrolle extensiones definidas por el usuario para IBM® Integration Bus en el lenguaje de programación C. Si está desarrollando extensiones definidas por el usuario utilizando el lenguaje de programación Java™, puede utilizar métodos de manejo de errores y excepciones Java estándar. Si, por ejemplo, IBM Integration Bus genera una excepción internamente, hay una excepción Java de clase MbExceptiondisponible.
El nodo de integración genera excepciones de C++ para manejar condiciones de error. Estas excepciones se detectan en las capas de software relevantes del nodo de integración y se manejan en consecuencia. No obstante, los programas escritos en C no pueden detectar excepciones de C++, y todas las excepciones que se generan pasan por alto, de forma predeterminada, todo el código de extensiones definidas por el usuario en C y se detectan en una capa superior del nodo de integración.
Por convenio, las funciones de utilidad normalmente utilizan el valor de retorno para devolver los datos solicitados; por ejemplo, la dirección o el manejador de un objeto de nodo de integración. A veces, el valor de retorno indica que se ha producido un error. Por ejemplo, si la dirección o el manejador de un objeto de nodo de integración no se ha podido recuperar, se devuelve cero (CCI_NULL_ADDR). Adicionalmente, el motivo de una condición de error se almacena en el parámetro de salida del código de retorno que, por convenio, forma parte del prototipo de función de todas las funciones de utilidad. Si la función de utilidad se ha completado correctamente y el valor de returnCode no es nulo, returnCode contiene CCI_SUCCESS. De lo contrario, contiene uno de los códigos de retorno que se describen aquí. Puede comprobar el valor de returnCode para determinar si una función de utilidad se ha realizado correctamente.
Si la llamada a una función de utilidad hace que el nodo de integración genere una excepción, el error es visible para la extensión definida por el usuario sólo si especificaba un valor para el parámetro returnCode correspondiente a dicha función de utilidad. Si se especificó un valor nulo para returnCode y se produce una excepción:
  • La extensión definida por el usuario no reconoce dicha excepción
  • La función de utilidad no vuelve a la extensión definida por el usuario
  • El control de la ejecución pasa a las capas superiores de la pila del nodo de integración para procesar la excepción
Por lo tanto, una extensión definida por el usuario no puede realizar su propia recuperación de errores. No obstante, si se especifica el parámetro returnCode y se produce una excepción, se devuelve un código de retorno de CCI_EXCEPTION. En este caso, se puede utilizar cciGetLastExceptionData o cciGetLastExceptionDataW (siendo la diferencia que cciGetLastExceptionDataW devuelve una estructura CCI_EXCEPTION_WIDE_ST que puede contener texto de rastreo Unicode) para obtener información de diagnóstico sobre el tipo de excepción que se ha producido. Los datos se devuelven en la estructura CCI_EXCEPTION_ST o CCI_EXCEPTION_WIDE_ST.
Si no hay ningún recurso para liberar, no establezca el argumento returnCode en la extensión definida por el usuario. Si no establece este argumento, las excepciones pueden ignorar las extensiones definidas por el usuario. A continuación, el nodo de integración puede manejar estas excepciones a niveles más altos de la pila IBM Integration Bus.
Se pueden devolver inserciones de mensajes en los miembros CCI_STRING_ST de la estructura CCI_EXCEPTION_ST. CCI_STRING_ST permite que la extensión definida por el usuario proporcione un almacenamiento intermedio para recibir todas las inserciones necesarias. El nodo de integración copia los datos en este almacenamiento intermedio y devuelve el número de bytes de salida y la longitud real de los datos. Si el almacenamiento intermedio no es lo suficientemente grande, no se copia ningún dato y se puede utilizar el miembro "dataLength" para aumentar el tamaño del almacenamiento intermedio, si es necesario.
La extensión definida por el usuario puede establecer un valor no nulo para returnCode y proporcionar su propia recuperación de errores, si fuera necesario. Las llamadas a la función de utilidad vuelven a la extensión definida por el usuario y pasan su estado mediante returnCode. Todas las excepciones que se producen en una función de utilidad se deben devolver al nodo de integración para llevar a cabo una recuperación adicional de errores; es decir, cuando se devuelve CCI_EXCEPTION en returnCode. Para ello, se llama a cciRethrowLastException después de que la extensión definida por el usuario ha completado su propio proceso de errores. La llamada a cciRethrowLastException hace que la interfaz C vuelva a generar la última excepción para que puedan manejarla otras capas del nodo de integración. De la misma manera que la llamada exit de C, cciRethrowLastException no regresa en este caso.
Si se produce una excepción y es detectada por una extensión definida por el usuario, la extensión no debe llamar a funciones de utilidad, excepto a cciGetLastExceptionDatacciGetLastExceptionDataW o cciRethrowLastException. Si se intenta llamar a otras funciones de utilidad, el comportamiento puede ser imprevisible y puede llegar a comprometer la integridad del nodo de integración.
Si una extensión definida por el usuario encuentra un error grave, se puede utilizar cciThrowException o cciThrowExceptionW para generar una excepción que el nodo de integración procese de manera correcta. Si se genera una excepción de este tipo, la información suministrada se graba en las anotaciones cronológicas del sistema (syslog o Eventviewer) si no se maneja la excepción. La información también se graba en el rastreo (si el rastreo está activo.

Tipos de excepciones y comportamiento del nodo de integración

El nodo de integración genera un conjunto de excepciones que pueden pasarse a una extensión definida por el usuario. Estas excepciones también las puede generar una extensión definida por el usuario cuando se encuentra una condición de error. Las clases de excepción son:
Fatal
Las excepciones fatales se generan cuando se produce una condición que impide que el proceso del nodo de integración continúe ejecutándose de forma segura o cuando la política del nodo de integración requiere la finalización del proceso. Como ejemplos de excepciones fatales están la imposibilidad de adquirir un recurso crítico del sistema o un error de software grave capturado internamente. El proceso del nodo de integración termina después de generar una excepción fatal. Se anotan las excepciones muy graves.
Recuperable
Estas excepciones se generan para errores que, aunque no son terminales por naturaleza, significan que debe finalizase el proceso del flujo de mensajes actual. Por ejemplo, las excepciones recuperables son datos no válidos en el contenido de un mensaje o un error de grabación de un mensaje en un nodo de salida. Cuando se genera una excepción recuperable, el proceso del mensaje actual se cancela en dicha hebra pero se vuelve a iniciar la ejecución de la hebra en su nodo de entrada. Las excepciones recuperables no se anotan.
Configuración
Las excepciones de configuración se generan cuando falla una solicitud de configuración. Esto puede ser debido a un error del formato de la solicitud de configuración o a un error de los datos. Cuando se genera una excepción de configuración, se rechaza la solicitud y se devuelve un mensaje de respuesta de error. No se anotan las excepciones de configuración.
Analizador
Estas excepciones las generan los analizadores de mensajes para los errores que impiden analizar el contenido del mensaje o crear una corriente de bits. El nodo de integración trata una excepción del analizador como una excepción recuperable. Generalmente, las excepciones de analizador se anotan, a menos que se consideren excepciones recuperables.
Conversión
Estas excepciones las generan las funciones de conversión de caracteres del nodo de integración si se encuentran datos no válidos al intentar la conversión a otro tipo de datos. El nodo de integración trata una excepción de conversión como una excepción recuperable y, por tanto, no se anota.
Usuario
Estas excepciones se generan cuando un nodo Throw genera una excepción definida por el usuario. Las excepciones de usuario se anotan.
Base de datos
Estas excepciones se generan cuando un sistema de gestión de bases de datos informa de un error durante la operación del nodo de integración. El nodo de integración trata una excepción de base de datos como una excepción recuperable. Las excepciones de base de datos se anotan si han generado una condición muy grave.
Fuente:https://www.ibm.com/support/knowledgecenter/es/SSMKHH_10.0.0/com.ibm.etools.mft.doc/as01430_.htm

Sobrecarga de Operadores

Sobrecarga de operadores.

Los operadores son un tipo de tokens que indican al compilador la realización de determinadas operaciones sobre variables u otros. La sobrecarga de operadores permite redefinir ciertos operadores, como '+' y '-', para usarlos con las clases que hemos definido. Se llama sobrecarga de operadores cuando reutilizando el mismo operador con un número de usos diferentes, y el compilador decide como usar ese operador dependiendo sobre qué opera.
La sobrecarga de operadores solo se puede utilizar con clases, no se pueden redefinir los operadores para los tipos simples predefinidos.
Los operadores lógicos && y || pueden ser sobrecargados para las clases definidas por el programador, pero no funcionaran como operadores de short circuit. Todos los miembros de la construcción lógica serán evaluados sin ningún problema en lo que se refiere a la salida. Naturalmente los operadores lógicos predefinidos continuaran siendo operadores de short circuit como era de esperar, pero no los sobrecargados.
Los operadores aceptan uno o varios operandos de tipo específico (alguno de los tipos básicos preconstruidos en el lenguaje), produciendo y/o modificando un valor de acuerdo con ciertas reglas. Sin embargo, C++ permite redefinir la mayor parte de ellos. Es decir, permite que puedan aceptar otro tipo de operandos (distintos de los tipos básicos) y seguir otro comportamiento, al tiempo que conservan el sentido y comportamiento originales cuando se usan con los operandos normales. Esta posibilidad recibe el nombre de sobrecarga del operador.

Permanencia de las leyes formales

El lenguaje C++ no impone ninguna restricción en la forma que adopte la sobrecarga de un operador. De forma que se puede conseguir que incluso operadores básicos como la suma (+), la asignación (=) o la identidad (==) adquieran para los tipos abstractos un carácter totalmente distinto del que adoptan para los tipos básicos. No obstante, lo normal, lógico, y aconsejable, es mantener la máxima homogeneidad conceptual en el polimorfismo. Es decir, que el efecto básico de los operadores (la imagen mental de su significado) se mantenga, aunque su implementación concreta varíe de una clase a otra. Por ejemplo, las definiciones de suma (+), asignación (=) e identidad (==) para los elementos de una clase C deberían garantizar que después de ejecutada la sentencia c = d; sobre instancias c y d de dicha clase, el resultado de (c == d) fuese true. El resultado de aplicar el constructor-copia para crear un objeto a partir de otro debería producir un nuevo objeto igual que el modelo.
Otro aspecto que debería mantenerse, es que los operadores que normalmente no tienen efectos laterales, se mantengan igualmente libres de tales efectos en sus versiones sobrecargadas. Lo anterior puede expresarse con otras palabras: debe procurarse que las propiedades formales de los operadores matemáticos se mantengan también en la versión sobrecargada. Por ejemplo, que la suma sea conmutativa y asociativa, que la identidad sea simétrica y transitiva. Al tratar la sobrecarga de los operadores relacionales se abunda en estos conceptos.

Sinopsis

A excepción de los que se detallan, el lenguaje C++ permite la sobrecarga los operadores estándar. La nueva versión del operador se diseña de forma que presente un comportamiento especial cuando los operandos sean instancias de clase. Por ejemplo, el operador de identidad = = podría ser definido en una hipotética clase Complejo para verificar la identidad de dos números complejos, al mismo tiempo que mantendría su uso normal cuando se utilizara con tipos básicos (int, float, char,).
Para distinguir unas de otras, a las versiones de los operadores preconstruidas en el lenguaje las denominamos versiones globales, mientras que a las definidas por el usuario, versiones sobrecargadas.

Operadores sobrecargables

El lenguaje C++ permite redefinir la funcionalidad de los siguientes operadores:


  +     -     *     /     %     ^     &
  |     ~     !     =     <     >     +=
  -=    *=    /=    %=    ^=    &=    |=
  <<    >>    >>=   <<=   ==    !=    <=
  >=    &&    ||    ++    --    ->*    ,
  ->    []    ()    new   new[]  delete delete[]

Los operadores +, -, * y & son sobrecargables en sus dos versiones, unaria y binaria. Es decir: suma binaria +; más unitario +; multiplicación *; indirección *; referencia & y manejo de bits &.

Es notable que C++ ofrece casos de operadores sobrecargados incluso en su Librería Estándar. Por ejemplo, los operadores == y != para la clase type_info. Sin embargo, la posibilidad de sobrecarga no se extiende a todos los operadores (ver las excepciones).

Limitaciones

La sobrecarga de un operador no puede cambiar el número de operandos o la asociatividad y precedencia del mismo. En otras palabras: se puede modificar su funcionalidad pero no su gramática original. Por ejemplo, un operador unario no puede ser transformado en binario y viceversa.
  • Los operadores globales no pueden ser sobrecargados.
  • No pueden definirse nuevos tokens como operadores. En caso necesario deben utilizarse funciones. Por ejemplo, no puede definirse ** como un token para representar la exponenciación (a ** b); en todo caso utilizar algo así: pow(a, b).
  • No es posible redefinir el sentido de un operador aplicado a un puntero. Por ejemplo, no es posible modificar el sentido del operador suma (+) entre un puntero y un entero (sentencia L.3).


  class CL { /* ... */ };
  CL c1, *cpt1 = &c1;
  CL* cpt2 = cpt1 + 5;        // L.3
    En otras palabras: no es posible modificar la aritmética de punteros sobrecargando sus operadores.

    Excepciones

    En la lista de los Operadores sobrecargables, puede verificarse que todos los operadores pueden ser sobrecargados, incluyendo new, new[ ], delete y delete[ ], excepto los siguientes:
    • Selector directo de componente .
    • Operador de indirección de puntero-a-miembro .*
    • Operador de acceso a ámbito  ::
    • Condicional ternario  ?:
    • Directivas de preprocesado # y # #
    • sizeof, typeid
    Los operadores asignación =; elemento de matriz [ ] ; invocación de función ( ) y selector indirecto de miembro -> pueden ser sobrecargados solamente como funciones-miembro no estáticas y no pueden ser sobrecargados para las enumeraciones. Cualquier intento de sobrecargar la versión global de estos operadores produce un error de compilación.
    Con la excepción de los anteriores ( =, [ ], ( ) y ->), los operadores también pueden ser sobrecargados para las enumeraciones y pueden utilizarse funciones-miembro estáticas.

    Excepciones

    En la lista de los Operadores sobrecargables, puede verificarse que todos los operadores pueden ser sobrecargados, incluyendo new, new[ ], delete y delete[ ], excepto los siguientes:
    • Selector directo de componente .
    • Operador de indirección de puntero-a-miembro .*
    • Operador de acceso a ámbito  ::
    • Condicional ternario  ?:
    • Directivas de preprocesado # y # #
    • sizeof, typeid
    Los operadores asignación =; elemento de matriz [ ] ; invocación de función ( ) y selector indirecto de miembro -> pueden ser sobrecargados solamente como funciones-miembro no estáticas y no pueden ser sobrecargados para las enumeraciones. Cualquier intento de sobrecargar la versión global de estos operadores produce un error de compilación.
    Con la excepción de los anteriores ( =, [ ], ( ) y ->), los operadores también pueden ser sobrecargados para las enumeraciones y pueden utilizarse funciones-miembro estáticas.

    La función-operador

    Los operadores C++ pueden considerarse funciones con identificadores un tanto especiales. Por ejemplo, cuando tenemos el operador de subíndice de matriz, x[y], donde x es un objeto de la clase X, el compilador lo traduce a la expresión: x.operator[](y). Es decir, lo interpreta como la invocación de un método de nombre operator[ ].
    Este comportamiento del compilador puede hacerse extensivo al resto de operadores, de forma que, cuando se trata de miembros de clases, si @ representa un operador binario, la expresión a @ b es en realidad una forma abreviada de representar la invocación de una función-miembro (método): a.operator@(b), o de una función externa equivalente: operator@(a, b).
    Igualmente, si @ representa un operador unario (por ejemplo, el operador preincremento ++, la expresión @ a es la forma abreviada de representar la invocación de una función-miembro que no acepte argumentos: a.operator@( ), o de una función externa equivalente que acepte un argumento: operator@(a).
    Estas funciones, denominadas función-operador, determinan el tipo de los operandos; el Lvalue y orden de evaluación que se aplicará cuando se utilice el operador. Como consecuencia, la sobrecarga de un operador se realiza bajo la forma de sobrecarga de la función-operador y su definición determinará el nuevo comportamiento. Como en el caso general de sobrecarga de funciones, el compilador distinguirá las diferentes funciones-operador por el contexto de la llamada (número y tipo de los argumentos).
    La palabra clave operator seguida del símbolo del operador conforma el identificador de la función-operador. Ejemplos:

     <tipo-devuelto> operator +  (/*...*/) {/*...*/} ;
      <tipo-devuelto> operator [] (/*...*/) {/*...*/} ;
      <tipo-devuelto> operator -  (/*...*/) {/*...*/} ;
      <tipo-devuelto> operator ->* (/*...*/) {/*...*/} ;
      <tipo-devuelto> operator =  (/*...*/) {/*...*/} ;
      <tipo-devuelto> operator= (/*...*/) {/*...*/} ;
    
    Es indiferente dejar un espacio entre la palabra operator y el símbolo del operador (las dos últimas líneas son equivalentes). Además la identificación operador ↔ función-operador no es solo interna, también puede ser utilizada explícitamente en el código. Una función-operador invocada con los argumentos apropiados, se comporta en cualquier sentencia como un operador con sus operandos. Por ejemplo:
      UnaClase c1, c2, c3;
      ...
      c2 = c1;              // L.3: Ok.  asignación
      c2.operator=(c1);     // L.4: Ok.  la misma asignación
      c3 = c1 + c2;         // L.5: suma y asignación
      c3.operator=(c1.operator+(c2));  // Ok. equivalente a L.5:
    
    Las sentencias L.3 y L.4 son equivalentes. Aunque legal, la expresión L.4 no es la forma usual de invocar al operador de asignación =.

    La función-operador no puede utilizar argumentos por defecto salvo en los casos que se autorizan expresamente. Tampoco pueden tener más o menos argumentos que los indicados en cada caso.
    La función-operador puede ser miembro o friend (función externa) de la clase para la que se define. Que se utilice una u otra forma es, a veces, cuestión de preferencia personal, pero en otras viene obligada. En cualquier caso, las funciones-operador son buenas candidatas para ser declaradas funciones inline
    • Se suelen declarar miembros de la clase los operadores unarios (de un solo operando), o los que modifican el primer operando (caso de los operadores de asignación). En estos casos el primer operando debe de ser necesariamente una instancia de esa clase, en concreto el objeto que constituye el argumento implícito. Por esta causa, salvo que sean declaradas funciones estáticas, puesto que el puntero this es incluido de forma implícita en la declaración, sólo hará falta incluir el segundo operando en la lista de argumentos de la función-operador.
    • Se suelen declarar friend los operadores que aceptan varios operandos sin modificarlos (por ejemplo los operadores aritméticos y lógicos). En estos casos se exige que al menos uno de sus operandos (argumentos) sea del tipo de la clase para la que se define (las funciones-operador que redefinen los operadores new y delete son la excepción de esta regla).


    Herencia y sobrecarga de operadores

    A excepción del operador de asignación simple = todas las funciones-operador sobrecargadas en una clase antecesora son heredadas en las clases derivadas. Si B es base de la clase D, un operador @ sobrecargado para B puede ser sobrecargado más tarde para D. Es decir, pueden coexistir las siguientes definiciones:
      B::operator@( ){ /* definicion para super-Clase */ }
      D::operator@( ){ /* definicion para clase derivada */ }
    



    Fuentes de: https://www.ecured.cu/Sobrecarga_de_operadores


    martes, 9 de abril de 2019

    Programacion Orientada A Objetos (Poo)

    Programación orientada a objetos (POO). Es un paradigma de programación que usa objetos y sus interacciones, para diseñar aplicaciones y programas informáticos. Está basado en varias técnicas, incluyendo herenciaabstracciónpolimorfismo y encapsulamiento. Su uso se popularizó a principios de la década de los años 1990. En la actualidad, existe variedad de lenguajes de programación que soportan la orientación a objetos.

    Los objetos son entidades que combinan estado (atributo), comportamiento (método) e identidad:

    El estado

    Está compuesto de datos, será uno o varios atributos a los que se habrán asignado unos valores concretos (datos).

    El comportamiento

    está definido por los procedimientos o métodos con que puede operar dicho objeto, es decir, qué operaciones se pueden realizar con él.

    La identidad

    Es una propiedad de un objeto que lo diferencia del resto, dicho con otras palabras, es su identificador (concepto análogo al de identificador de una variable o una constante).
    Un objeto contiene toda la información que permite definirlo e identificarlo frente a otros objetos pertenecientes a otras clases e incluso frente a objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos. A su vez, los objetos disponen de mecanismos de interacción llamados métodos, que favorecen la comunicación entre ellos. Esta comunicación favorece a su vez el cambio de estado en los propios objetos. Esta característica lleva a tratarlos como unidades indivisibles, en las que no se separa el estado y el comportamiento.
    Los métodos (comportamiento) y atributos (estado) están estrechamente relacionados por la propiedad de conjunto. Esta propiedad destaca que una clase requiere de métodos para poder tratar los atributos con los que cuenta. El programador debe pensar indistintamente en ambos conceptos, sin separar ni darle mayor importancia a alguno de ellos. Hacerlo podría producir el hábito erróneo de crear clases contenedoras de información por un lado y clases con métodos que manejen a las primeras por el otro. De esta manera se estaría realizando una programación estructurada camuflada en un lenguaje de programación orientado a objetos.
    La POO difiere de la programación estructurada tradicional, en la que los datos y los procedimientos están separados y sin relación, ya que lo único que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programación estructurada anima al programador a pensar sobre todo en términos de procedimientos o funciones, y en segundo lugar en las estructuras de datos que esos procedimientos manejan. En la programación estructurada sólo se escriben funciones que procesan datos. Los programadores que emplean POO, en cambio, primero definen objetos para luego enviarles mensajes solicitándoles que realicen sus métodos por sí mismos.

    Origen

    Los conceptos de la programación orientada a objetos tienen origen en Simula 67, un lenguaje diseñado para hacer simulaciones, creado por Ole-Johan Dahl y Kristen Nygaard del Centro de Cómputo Noruego en Oslo. En este centro, se trabajaba en simulaciones de naves, que fueron confundidas por la explosión combinatoria de cómo las diversas cualidades de diferentes naves podían afectar unas a las otras. La idea ocurrió para agrupar los diversos tipos de naves en diversas clases de objetos, siendo responsable cada clase de objetos de definir sus propios datos y comportamientos. Fueron refinados más tarde en Smalltalk, que fue desarrollado en Simula en Xerox PARC (cuya primera versión fue escrita sobre Basic) pero diseñado para ser un sistema completamente dinámico en el cual los objetos se podrían crear y modificar "en marcha" (en tiempo de ejecución) en lugar de tener un sistema basado en programas estáticos.
    La programación orientada a objetos tomó posición como el estilo de programación dominante a mediados de los años ochenta, en gran parte debido a la influencia de C++, una extensión del lenguaje de programación C. Su dominación fue consolidada gracias al auge de las Interfaces gráficas de usuario, para las cuales la programación orientada a objetos está particularmente bien adaptada. En este caso, se habla también de programación dirigida por eventos.
    Las características de orientación a objetos fueron agregadas a muchos lenguajes existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp, Pascal, entre otros. La adición de estas características a los lenguajes que no fueron diseñados inicialmente para ellas condujo a menudo a problemas de compatibilidad y en la capacidad de mantenimiento del código. Los lenguajes orientados a objetos "puros", por su parte, carecían de las características de las cuales muchos programadores habían venido a depender. Para saltar este obstáculo, se hicieron muchas tentativas para crear nuevos lenguajes basados en métodos orientados a objetos, pero permitiendo algunas características imperativas de maneras "seguras". El Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado lenguaje con esos objetivos pero ahora ha sido esencialmente reemplazado por Java, en gran parte debido a la aparición de Internet, y a la implementación de la máquina virtual de Java en la mayoría de navegadores. PHP en su versión 5 se ha modificado, soporta una orientación completa a objetos, cumpliendo todas las características propias de la orientación a objetos.
    Conceptos fundamentales
    La programación orientada a objetos es una forma de programar que trata de encontrar una solución a estos problemas. Introduce nuevos conceptos, que superan y amplían conceptos antiguos ya conocidos. Entre ellos destacan los siguientes:

    Clase

    Definiciones de las propiedades y comportamiento de un tipo de objeto concreto. La instanciación es la lectura de estas definiciones y la creación de un objeto a partir de ellas.

    Herencia

    Es la facilidad mediante la cual la clase D hereda en ella cada uno de los atributos y operaciones de C, como si esos atributos y operaciones hubiesen sido definidos por la misma D. Por lo tanto, puede usar los mismos métodos y variables publicas declaradas en C. Los componentes registrados como "privados" (private) también se heredan, pero como no pertenecen a la clase, se mantienen escondidos al programador y sólo pueden ser accedidos a través de otros métodos públicos. Esto es así para mantener hegemónico el ideal de OOP.

    Objeto

    Entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad (métodos) los mismos que consecuentemente reaccionan a eventos. Se corresponde con los objetos reales del mundo que nos rodea, o a objetos internos del sistema (del programa). Es una instancia a una clase.

    Método

    Algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un "mensaje". Desde el punto de vista del comportamiento, es lo que el objeto puede hacer. Un método puede producir un cambio en las propiedades del objeto, o la generación de un "evento" con un nuevo mensaje para otro objeto del sistema.

    Evento

    Es un suceso en el sistema (tal como una interacción del usuario con la máquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente. También se puede definir como evento, a la reacción que puede desencadenar un objeto, es decir la acción que genera.

    Mensaje

    Una comunicación dirigida a un objeto, que le ordena que ejecute uno de sus métodos con ciertos parámetros asociados al evento que lo generó.

    Propiedad o atributo

    Contenedor de un tipo de datos asociados a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto y esto se define como sus características predeterminadas, y cuyo valor puede ser alterado por la ejecución de algún método.

    Estado interno

    Es una variable que se declara privada, que puede ser únicamente accedida y alterada por un método del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos). No es visible al programador que maneja una instancia de la clase.

    Componentes de un objeto

    Atributos, identidad, relaciones y métodos.

    Identificación de un objeto

    Un objeto se representa por medio de una tabla o entidad que esté compuesta por sus atributos y funciones correspondientes.
    En comparación con un lenguaje imperativo, una "variable", no es más que un contenedor interno del atributo del objeto o de un estado interno, así como la "función" es un procedimiento interno del método del objeto.
    Características de la POO
    Existe un acuerdo acerca de qué características contempla la "orientación a objetos", las características siguientes son las más importantes:

    Abstracción

    Denota las características esenciales de un objeto, donde se capturan sus comportamientos.Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin revelar cómo se implementan estas características. Los procesos, las funciones o los métodos pueden también ser abstraídos y cuando lo están, una variedad de técnicas son requeridas para ampliar una abstracción.El proceso de abstracción permite seleccionar las características relevantes dentro de un conjunto e identificar comportamientos comunes para definir nuevos tipos de entidades en el mundo real. La abstracción es clave en el proceso de análisis y diseño orientado a objetos, ya que mediante ella podemos llegar a armar un conjunto de clases que permitan modelar la realidad o el problema que se quiere atacar.

    Encapsulamiento

    Significa reunir a todos los elementos que pueden considerarse pertenecientes a una misma entidad, al mismo nivel de abstracción. Esto permite aumentar la cohesión de los componentes del sistema. Algunos autores confunden este concepto con el principio de ocultación, principalmente porque se suelen emplear conjuntamente.

    Principio de ocultación

    Cada objeto está aislado del exterior, es un módulo natural, y cada tipo de objeto expone una interfaz a otros objetos que especifica cómo pueden interactuar con los objetos de la clase. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas, solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas, eliminando efectos secundarios e interacciones inesperadas. Algunos lenguajes relajan esto, permitiendo un acceso directo a los datos internos del objeto de una manera controlada y limitando el grado de abstracción. La aplicación entera se reduce a un agregado o rompecabezas de objetos.

    Polimorfismo

    Comportamientos diferentes, asociados a objetos distintos, pueden compartir el mismo nombre, al llamarlos por ese nombre se utilizará el comportamiento correspondiente al objeto que se esté usando. O dicho de otro modo, las referencias y las colecciones de objetos pueden contener objetos de diferentes tipos, y la invocación de un comportamiento en una referencia producirá el comportamiento correcto para el tipo real del objeto referenciado. Cuando esto ocurre en "tiempo de ejecución", esta última característica se llama asignación tardía o asignación dinámica. Algunos lenguajes proporcionan medios más estáticos (en "tiempo de compilación") de polimorfismo, tales como las plantillas y la sobrecarga de operadores de C++.

    Herencia

    Las clases no están aisladas, sino que se relacionan entre sí, formando una jerarquía de clasificación. Los objetos heredan las propiedades y el comportamiento de todas las clases a las que pertenecen. La herencia organiza y facilita el polimorfismo y el encapsulamiento permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes. Estos pueden compartir (y extender) su comportamiento sin tener que volver a implementarlo. Esto suele hacerse habitualmente agrupando los objetos en clases y estas en árboles o enrejados que reflejan un comportamiento común. Cuando un objeto hereda de más de una clase se dice que hay herencia múltiple.

    Recolección de basura

    La recolección de basura o garbage collector es la técnica por la cual el entorno de objetos se encarga de destruir automáticamente, y por tanto desvincular la memoria asociada, los objetos que hayan quedado sin ninguna referencia a ellos. Esto significa que el programador no debe preocuparse por la asignación o liberación de memoria, ya que el entorno la asignará al crear un nuevo objeto y la liberará cuando nadie lo esté usando. En la mayoría de los lenguajes híbridos que se extendieron para soportar el Paradigma de Programación Orientada a Objetos como C++ u Object Pascal, esta característica no existe y la memoria debe desasignarse manualmente.

    Entre los lenguajes orientados a objetos se destacan los siguientes

    • ABAP
    • ABL Lenguaje de programación de OpenEdge de Progress Software
    • ActionScript
    • ActionScript 3
    • Ada
    • C++
    • C#
    • Clarion
    • Clipper (lenguaje de programación) (Versión 5.x con librería de objetos Class(y))
    • D
    • Object Pascal (Delphi)
    • Gambas
    • Harbour
    • Eiffel
    • Java
    • JavaScript (la herencia se realiza por medio de la programación basada en prototipos)
    • Lexico (en castellano)
    • Objective-C
    • Ocaml
    • Oz
    • R
    • Perl (soporta herencia múltiple. La resolución se realiza en preorden, pero puede modificarse al algoritmo linearization C3 por medio del módulo Class::C3 en CPAN)
    • PHP (a partir de su versión 5)
    • PowerBuilder
    • Python
    • Ruby
    • Smalltalk (Proyecto investigativo. Influenció a Java.)
    • Magik (SmallWorld)
    • Vala
    • Visual BASIC.NET
    • Visual FoxPro (en su versión 6)
    • Visual Basic 6.0
    • Visual Objects
    • XBase++
    • Lenguaje DRP
    • Lenguaje de programación Scala (lenguaje usado por Twitter).
    Muchos de estos lenguajes de programación no son puramente orientados a objetos, sino que son híbridos que combinan la POO con otros paradigmas.
    Al igual que C++ otros lenguajes, como OOCOBOL, OOLISP, OOPROLOG y Object REXX, han sido creados añadiendo extensiones orientadas a objetos a un lenguaje de programación clásico.

    Un nuevo paso en la abstracción de paradigmas de programación es la Programación Orientada a Aspectos (POA). Aunque es todavía una metodología en estado de maduración, cada vez atrae a más investigadores e incluso proyectos comerciales en todo el mundo.