EIF201-Progra-I

Curso de programación Universidad Nacional de Costa Rica

View the Project on GitHub mikeguzman/EIF201-Progra-I

Relaciones de objeto

Hay muchos tipos diferentes de relaciones que dos objetos pueden tener en la vida real, y usamos palabras específicas de “tipo de relación” para describir estas relaciones. Por ejemplo: una forma cuadrada “es-a”. Un carro “tiene-un” volante. Un programador de computadoras “usa un teclado”. Una flor “depende” de una abeja para la polinización. Un estudiante es un “miembro de” una clase. Y su cerebro existe como “parte de usted”.

Composición

Agregación

Asociación

Tabla de resumen de la diferencia entre composición, agregación y asociación:

Propiedad Composición Agregación Asociación
Tipo de Relación Todo/parte Todo/parte Sin relación
Los miembros pertenecen a multiples clases No
La existencia de los miembros es administrado por la clase No No
Dirección Unidireccional Unidireccional Unidireccional o bidireccional
Verbo relacionado Parte-de Tiene-a Utiliza-a

Dependencia

#include <iostream>
 
class Point
{
private:
    double m_x, m_y, m_z;
 
public:
    Point(double x=0.0, double y=0.0, double z=0.0): m_x(x), m_y(y), m_z(z)
    {
    }
 
    friend std::ostream& operator<< (std::ostream &out, const Point &point);
};
 
std::ostream& operator<< (std::ostream &out, const Point &point)
{
    // Since operator<< is a friend of the Point class, we can access Point's members directly.
    out << "Point(" << point.m_x << ", " << point.m_y << ", " << point.m_z << ")";
 
    return out;
}
 
int main()
{
    Point point1(2.0, 3.0, 4.0);
 
    std::cout << point1;
 
    return 0;
}

Un buen ejemplo de una dependencia es std :: cout (de tipo std :: ostream). Las clases que usan std :: cout lo usan para realizar la tarea de imprimir algo en la consola, pero no de otra manera.

Clases contenedoras

El uso de contenedores se usa diariamente, un ejemplo es el cereal para el desayuno viene en una caja, las páginas de un libro vienen dentro de una cubierta y una encuadernación, y puede almacenar cualquier cantidad de artículos en contenedores en su garaje. Sin contenedores, sería extremadamente inconveniente trabajar con muchos de estos objetos.

Del mismo modo, una clase contenedor es una clase diseñada para contener y organizar múltiples instancias de otro tipo (ya sea otra clase o un tipo fundamental). Existen muchos tipos diferentes de clases de contenedor, cada una de las cuales tiene varias ventajas, desventajas y restricciones en su uso. Con mucho, el contenedor más utilizado en la programación es el arreglo. Aunque C ++ tiene una funcionalidad incorporada, los programadores a menudo usarán una clase de contenedor de matriz (std :: array o std :: vector) en su lugar debido a los beneficios adicionales que brindan. A diferencia de las matrices integradas, las clases de contenedor de matrices generalmente proporcionan un cambio de tamaño dinámico (cuando se agregan o eliminan elementos), recuerdan su tamaño cuando se pasan a las funciones y realizan la verificación de límites. Esto no solo hace que las clases de contenedor de matriz sean más convenientes que las matrices normales, sino también más seguras.

Las clases de contenedores suelen implementar un conjunto mínimo de funcionalidades bastante estandarizado. La mayoría de los contenedores bien definidos incluirán funciones que:

Tipos de contenedores

Las clases de contenedores generalmente vienen en dos variedades diferentes.

  1. Los contenedores de valor son composiciones que almacenan copias de los objetos que contienen (y, por lo tanto, son responsables de crear y destruir esas copias).
  2. Los contenedores de referencia son agregaciones que almacenan punteros o referencias a otros objetos (y, por lo tanto, no son responsables de la creación o destrucción de esos objetos).

A diferencia de la vida real, donde los contenedores pueden contener cualquier tipo de objeto que coloque en ellos, en C ++, los contenedores generalmente solo contienen un tipo de datos. Por ejemplo, si tiene una matriz de enteros, solo contendrá enteros. A diferencia de otros lenguajes, muchos contenedores C ++ no le permiten mezclar tipos arbitrariamente. Si necesita contenedores para contener enteros y dobles, generalmente tendrá que escribir dos contenedores separados para hacerlo (o usar plantillas, que es una característica avanzada de C ++). A pesar de las restricciones en su uso, los contenedores son inmensamente útiles y hacen que la programación sea más fácil, segura y rápida.

IntArray.h

#ifndef INTARRAY_H
#define INTARRAY_H
 
#include <cassert> // for assert()
 
class IntArray
{
private:
    int m_length;
    int *m_data;
 
public:
    IntArray():
        m_length(0), m_data(nullptr)
    {
    }
 
    IntArray(int length):
        m_length(length)
    {
        assert(length >= 0);
        if (length > 0)
            m_data = new int[length];
        else
            m_data = nullptr;
    }
 
    ~IntArray()
    {
        delete[] m_data;
        // we don't need to set m_data to null or m_length to 0 here, since the object will be destroyed immediately after this function anyway
    }
 
    void erase()
    {
        delete[] m_data;
        // We need to make sure we set m_data to nullptr here, otherwise it will
        // be left pointing at deallocated memory!
        m_data = nullptr;
        m_length = 0;
    }
 
    int& operator[](int index)
    {
        assert(index >= 0 && index < m_length);
        return m_data[index];
    }
 
    // reallocate resizes the array.  Any existing elements will be destroyed.  This function operates quickly.
    void reallocate(int newLength)
    {
        // First we delete any existing elements
        erase();
 
        // If our array is going to be empty now, return here
        if (newLength <= 0)
            return;
 
        // Then we have to allocate new elements
        m_data = new int[newLength];
        m_length = newLength;
    }
 
    // resize resizes the array.  Any existing elements will be kept.  This function operates slowly.
    void resize(int newLength)
    {
        // if the array is already the right length, we're done
        if (newLength == m_length)
            return;
 
        // If we are resizing to an empty array, do that and return
        if (newLength <= 0)
        {
            erase();
            return;
        }
 
        // Now we can assume newLength is at least 1 element.  This algorithm
        // works as follows: First we are going to allocate a new array.  Then we
        // are going to copy elements from the existing array to the new array.
        // Once that is done, we can destroy the old array, and make m_data
        // point to the new array.
 
        // First we have to allocate a new array
        int *data = new int[newLength];
 
        // Then we have to figure out how many elements to copy from the existing
        // array to the new array.  We want to copy as many elements as there are
        // in the smaller of the two arrays.
        if (m_length > 0)
        {
            int elementsToCopy = (newLength > m_length) ? m_length : newLength;
 
            // Now copy the elements one by one
            for (int index=0; index < elementsToCopy ; ++index)
                data[index] = m_data[index];
        }
 
        // Now we can delete the old array because we don't need it any more
        delete[] m_data;
 
        // And use the new array instead!  Note that this simply makes m_data point
        // to the same address as the new array we dynamically allocated.  Because
        // data was dynamically allocated, it won't be destroyed when it goes out of scope.
        m_data = data;
        m_length = newLength;
    }
 
    void insertBefore(int value, int index)
    {
        // Sanity check our index value
        assert(index >= 0 && index <= m_length);
 
        // First create a new array one element larger than the old array
        int *data = new int[m_length+1];
 
        // Copy all of the elements up to the index
        for (int before=0; before < index; ++before)
            data [before] = m_data[before];
 
        // Insert our new element into the new array
        data [index] = value;
 
        // Copy all of the values after the inserted element
        for (int after=index; after < m_length; ++after)
            data[after+1] = m_data[after];
 
        // Finally, delete the old array, and use the new array instead
        delete[] m_data;
        m_data = data;
        ++m_length;
    }
 
    void remove(int index)
    {
        // Sanity check our index value
        assert(index >= 0 && index < m_length);
 
        // If we're removing the last element in the array, we can just erase the array and return early
        if (m_length == 1)
        {
            erase();
            return;
        }
 
        // First create a new array one element smaller than the old array
        int *data = new int[m_length-1];
 
        // Copy all of the elements up to the index
        for (int before=0; before  < index; ++before)
            data[before] = m_data[before];
 
        // Copy all of the values after the removed element
        for (int after=index+1; after < m_length; ++after )
            data[after-1] = m_data[after];
 
        // Finally, delete the old array, and use the new array instead
        delete[] m_data;
        m_data = data;
        --m_length;
    }
 
    // A couple of additional functions just for convenience
    void insertAtBeginning(int value) { insertBefore(value, 0); }
    void insertAtEnd(int value) { insertBefore(value, m_length); }
 
    int getLength() { return m_length; }
};
 
#endif

main.cpp

#include <iostream>
#include "IntArray.h"
 
int main()
{
    // Declare an array with 10 elements
    IntArray array(10);
 
    // Fill the array with numbers 1 through 10
    for (int i=0; i<10; i++)
        array[i] = i+1;
 
    // Resize the array to 8 elements
    array.resize(8);
 
    // Insert the number 20 before element with index 5
    array.insertBefore(20, 5);
 
    // Remove the element with index 3
    array.remove(3);
 
    // Add 30 and 40 to the end and beginning
    array.insertAtEnd(30);
    array.insertAtBeginning(40);
 
    // Print out all the numbers
    for (int j=0; j<array.getLength(); j++)
        std::cout << array[j] << " ";
 
    return 0;
}

Página de Inicio