Ejemplos capítulos 27 a 31

Ejemplo 31.1

Ahora estamos en disposición de empezar a usar clases para modelar algunos problemas cotidianos.

Empezaremos por las fracciones. Ya hemos hecho algunas aproximaciones usando estructuras, ahora usaremos una clase, y en sucesivos capítulos, iremos añadiendo más refinamientos.

// Clase fracción
// (C) 2009 Con Clase
// Salvador Pozo

#include <iostream>

using namespace std;

class fraccion {
    public:
        fraccion(int n=0, int d=0) : numerador(n), denominador(d) {
            Simplificar();
        }
        void Simplificar();
        void Mostrar();
    private:
        int numerador;
        int denominador;
        int MCD(int, int);
};

void fraccion::Simplificar() {
    int mcd = MCD(numerador, denominador);
    numerador /= mcd;
    denominador /= mcd;
}

void fraccion::Mostrar() {
    cout << numerador << "/" << denominador << endl;
}

int fraccion::MCD(int a, int b) {
    if(a < b) return MCD(b,a);
    if(b == 0) return a;
    return MCD(b, a % b);
}

int main() {
    fraccion f1(234, 2238);
    fraccion f2(64, 1024);
    
    f1.Mostrar();
    f2.Mostrar();
    return 0;
}

Ejecutar este código en codepad.

Hemos invocado al método Simplificar dentro del constructor, de ese modo, la fracción siempre se almacenará simplificada cuando se cree. Probablemente esto haga que sea innecesario que Simplificar sea pública, ya que cualquier llamada desde el exterior no afectará a la fracción. Podríamos haberla declarado como privada.

Ejemplo 31.2

Añadamos una función Sumar a esta clase, que nos sirva para sumar dos fracciones:

// Clase fracción
// (C) 2009 Con Clase
// Salvador Pozo

#include <iostream>

using namespace std;

class fraccion {
    public:
        fraccion(int n=0, int d=0) : numerador(n), denominador(d) {
            Simplificar();
        }
        void Simplificar();
        void Sumar(fraccion);
        void Mostrar();
    private:
        int numerador;
        int denominador;
        int MCD(int, int);
};

void fraccion::Simplificar() {
    int mcd = MCD(numerador, denominador);
    numerador /= mcd;
    denominador /= mcd;
}

void fraccion::Sumar(fraccion f2) {
    numerador = numerador*f2.denominador+denominador*f2.numerador;
    denominador = denominador*f2.denominador;
    Simplificar();
}

void fraccion::Mostrar() {
    cout << numerador << "/" << denominador << endl;
}

int fraccion::MCD(int a, int b) {
    if(a &lt; b) return MCD(b,a);
    if(b == 0) return a;
    return MCD(b, a % b);
}

int main() {
    fraccion f1(234, 2238);
    fraccion f2(64, 1024);
    
    f1.Mostrar();
    f2.Mostrar();

    f1.Sumar(f2);
    f1.Mostrar();

    return 0;
}

Ejecutar este código en codepad.

Más adelante veremos como sobrecargar el operador suma para implementar esta función.

Ejemplo 31.3

En este ejemplo crearemos una clase "tonta", que nos servirá para seguir la pista a constructores y destructores a medida que son invocados de forma implícita o explícita. En próximos capítulos añadiremos más cosas para monitorizar otras características.

// Clase tonta
// (C) 2009 Con Clase
// Salvador Pozo

#include <iostream>

using namespace std;

class tonta {
    public:
        tonta();
        tonta(int);
        tonta(const tonta&);
        ~tonta();
        int Modifica(int);
        int Lee();
    private:
        int valor;
};

tonta::tonta() : valor(0) {
    cout << "Constructor sin parámetros (0)" << endl;
}

tonta::tonta(int v) : valor(v) {
    cout << "Constructor con un parámetro (" << v << ")" << endl;
}

tonta::tonta(const tonta &t) : valor(t.valor) {
    cout << "Constructor copia (" << t.valor << ")" << endl;
}

tonta::~tonta() {
    cout << "Destructor (" << valor << ")" << endl;
}

int tonta::Modifica(int v) {
    int retval = valor;

    cout << "Modificar valor (" << valor << ") -> (" << v << ")" << endl;
    valor = v;
    return retval;
}

int tonta::Lee() {
    return valor;
}

int main() {
    tonta obj1;
    tonta *obj2;
    tonta obj3 = obj1;

    obj2 = new tonta(2);

    obj1.Modifica(3);
    cout << "Objeto1: " << obj1.Lee() << endl;
    cout << "Objeto2: " << obj2->Lee() << endl;
    cout << "Objeto3: " << obj3.Lee() << endl;

    delete obj2;

    return 0;
}

Ejecutar este código en codepad.

Viendo la salida de este programa:

Constructor sin parámetros (0)
Constructor copia (0)
Constructor con un parámetro (2)
Modificar valor (0) -> (3)
Objeto1: 3
Objeto2: 2
Objeto3: 0
Destructor (2)
Destructor (0)
Destructor (3)

vemos que para obj1 se invoca al constructor sin parámetros cuando es declarado, y que para obj2 se invoca al constructor con un parámetro cuando es invocado explícitamente junto al operador new.

Con los destructores pasa lo mismo, para obj2 se incova al destruir el objeto mediante el operador delete, y para obj1 se invoca de forma implícita al terminar su ámbito temporal.

Comentarios de los usuarios (1)

gregorio esteban
2015-09-28 12:33:52

Erratas en Curso de C++

"Ejemplos capítulos 27 a 31"

En el ejemplo 31.2 linea 41

Dice:

if(a &lt; b) return MCD(b,a);

Debe decir:

if(a < b) return MCD(b,a);

El ultimo parrafo de "Ejemplos capitulos 27 a 31"

Dice:

Con los destructores pasa lo mismo, para obj2 se incova al destruir el objeto mediante el operador delete, y para obj1 se invoca de forma implícita al terminar su ámbito temporal.

Debe decir:

Con los destructores pasa lo mismo, para obj2 se invoca al destruir el objeto mediante el operador delete, y para obj1 se invoca de forma implícita al terminar su ámbito temporal.

Excelente trabajo, un saludo cordial.