Características básicas de los lenguajes orientados a objetos.
Created: 2025-02-25 mar 18:36
Mientras que cuando los vemos desde el prisma del desarrollo de software, los objetos son:
Aquel que dispone de las siguientes características:
¿Qué es entonces el tiempo de enlace?:
Es el instante de tiempo en el que se determina o identifica el trozo de código, p.e. una función que ha de ser llamada tras el envío de un mensaje, o el significado de una ‘construcción’ especial en memoria, p.e. el tipo exacto de una variable o un dato.
int n;
auto
, en las cuales el
compilador infiere el tipo a partir de la expresión de
inicialización de la variable: auto n = 3;
python
, smalltalk
, perl
, etc…C
, C++
, Java
, C#
, D
, etc…Si retomamos el concepto del principio de sustitución y una declaración de clases con herencia como esta:
class Automaton {
public:
void compute () {...}
};
class Robot : public Automaton {...}; // Es Un
// Un robot es un automata.
El principio de sustitución nos dice que en cualquier lugar de
nuestro código donde podamos usar un dato de clase o tipo
Automata
, podremos usar uno de clase Robot
, p.e.:
Robot* r = new Robot;
r->compute ();
Automaton* aa[100];
aa[0] = r;
aa[1] = new Automaton;
Tiene consecuencias, p.e., con el código a invocar (método) en respuesta a un mensaje recibido.
class Automaton {
public:
virtual void compute () {...} // compute tiene ahora enlace dinámico (virtual)
};
class Robot : public Automaton {
void compute () {...} // Se redefine en clases derivadas
// no es necesario virtual, ya se sabe.
};
class ChessPlayer : public Automaton {
void compute () {...}
};
¿Que crees que pasará con este código?
Automaton* aa[10];
aa[0] = new Automaton; aa[1] = new ChessPlayer;
aa[2] = new Robot; aa[3] = new Automaton;
...
for (auto ai = 0; ai < 10; ai++) aa[ai]->compute();
obj.operation()
(envío del
mensaje).robot.avanzarLineaRecta(20);
object.method (parameters)
objectPtr->method (parameters)
Java
, C#
, D
, etc… sólo se emplea la forma
object.method (parameters)
.DashBoard
representa un nombre de una clase, usar un método de clase con ese
identificador lo haríamos así: DashBoard::classMethod (parameters)
// Copyright (C) 2020-2023 Programacion-II
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <iostream>
#include <cstdint>
class FiguraGeometrica {
public:
FiguraGeometrica() {
// std::cout << "Hola, soy una FG tambien\n";
inc_count();
}
virtual ~FiguraGeometrica() { std::cout << "FiguraGeometrica::DESTRUCTOR\n"; }
// Prueba a usar esta definición de dibujar en lugar de la que hay
// mas adelante. Si se produce algún error de compilación trata de
// resolverlo.
// virtual void dibujar() = 0;
// FiguraGeometrica::dibujar tiene enlace dinámico
virtual void dibujar() { std::cout << "FiguraGeometrica::dibujar\n"; };
static uint32_t get_count() { return count; }
static void inc_count() { count++; }
private:
//static uint32_t count; // Probar a inicializar aqui.
// O de este otro mode en C++17 o superior
// inline static uint32_t count = 0;
};
uint32_t FiguraGeometrica::count = 0;
using FiguraGeometricaPtr = FiguraGeometrica*;
class Circulo : public FiguraGeometrica {
public:
Circulo() { std::cout << "Hola, soy un circulo\n"; }
virtual ~Circulo() { std::cout << "Circulo::DESTRUCTOR\n"; }
void dibujar() { std::cout << "Circulo::dibujar\n"; }
};
class Rectangulo : public FiguraGeometrica {
public:
Rectangulo() { std::cout << "Hola, soy un rectangulo\n"; };
virtual ~Rectangulo() { std::cout << "Rectangulo::DESTRUCTOR\n"; }
void dibujar() { std::cout << "Rectangulo::dibujar\n"; }
};
// Comprueba lo sencillo que es añadir una nueva clase al
// diseño. Comparalo con lo que tendrias que hacer para añadir una
// nueva clase en la versión de C no orientada a objetos.
// class Triangulo : public FiguraGeometrica {
// public:
// Triangulo() {
// std::cout << "Hola, soy un triangulo\n";
// };
// virtual ~Triangulo() {
// std::cout << "Triangulo::DESTRUCTOR\n";
// }
// void dibujar() {
// std::cout << "Triangulo::dibujar\n";
// }
// };
int main () {
FiguraGeometricaPtr vfg[5] = {nullptr,nullptr,nullptr,nullptr,nullptr};
vfg[0] = new Circulo;
vfg[1] = new Circulo;
vfg[2] = new Rectangulo;
vfg[3] = new Rectangulo;
// En vfg[4] guardamos una FiguraGeometrica o un Triangulo.
vfg[4] = new FiguraGeometrica;
// vfg[4] = new Triangulo;
for (int f = 0; f < 5; f++) {
std::cout << "vfg[" << f << "]: ";
vfg[f]->dibujar();
}
for (int f = 0; f < 5; f++) {
delete vfg[f];
}
std::cout << "total de FG creadas: " << FiguraGeometrica::get_count() << '\n';
return 0;
}
/*
* Copyright (C) 2020-2022 Programacion-II
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
/*
* Trata de añadir una 'clase' Triangulo a este ejemplo. Compara todos
* los pasos a realizar con los que tendrias que hacer en la versión
* orientada a objetos en C++
*/
enum TipoFigura { FG, CIRCULO, RECTANGULO };
typedef struct FiguraGeometrica {
enum TipoFigura t;
} FiguraGeometrica;
typedef struct Circulo {
enum TipoFigura t;
} Circulo;
typedef struct Rectangulo {
enum TipoFigura t;
} Rectangulo;
typedef FiguraGeometrica* FiguraGeometricaPtr;
typedef Circulo* CirculoPtr;
typedef Rectangulo* RectanguloPtr;
void FiguraGeometrica_dibujar(FiguraGeometricaPtr this) {
printf("FiguraGeometrica::dibujar\n");
}
void Circulo_dibujar(CirculoPtr this) {
printf("Circulo::dibujar\n");
}
void Rectangulo_dibujar(RectanguloPtr this) {
printf("Rectangulo::dibujar\n");
}
int main(int argc, char *argv[]) {
FiguraGeometricaPtr vfg[5] = {NULL, NULL, NULL, NULL, NULL};
vfg[0] = malloc (sizeof (Circulo));
vfg[0]->t = CIRCULO;
vfg[1] = malloc (sizeof (Circulo));
vfg[1]->t = CIRCULO;
vfg[2] = malloc (sizeof (Rectangulo));
vfg[2]->t = RECTANGULO;
vfg[3] = malloc (sizeof (Rectangulo));
vfg[3]->t = RECTANGULO;
vfg[4] = malloc (sizeof (Circulo));
vfg[4]->t = CIRCULO;
for (int f = 0; f < 5; f++) {
switch (vfg[f]->t) {
case FG:
FiguraGeometrica_dibujar(vfg[f]);
break;
case CIRCULO:
Circulo_dibujar((CirculoPtr) vfg[f]);
break;
case RECTANGULO:
Rectangulo_dibujar((RectanguloPtr) vfg[f]);
break;
}
}
for (int f = 0; f < 5; f++) {
free(vfg[f]);
}
return 0;
}