Lección 20 · 20 de 20
Proyecto: editor de formas · C++
Proyecto final del curso avanzado de C++: un editor de formas con clases, polimorfismo, unique_ptr y algoritmos de la STL, listo para F9 en DMarlon Studio.

Este proyecto reúne lo visto en el curso. Shape es la interfaz común: toda forma tiene un nombre y un area() virtual puro, y la base lleva un destructor virtual porque las formas se destruirán a través de punteros a Shape. Circle y Rect heredan de ella, construyen la parte común con Shape(n) en su lista de inicialización y calculan el área cada una a su manera.
El lienzo es un std::vector<std::unique_ptr<Shape>>: guarda formas de tipos distintos y es su dueño. Cada std::make_unique<Rect>(...) crea una forma y se la entrega. En todo el programa no hay ni un delete, y no se pierde memoria.
Las operaciones del editor son algoritmos de la STL con lambdas. remove_if con erase quita las formas de menos de una unidad de área (el punto «dot», de 0,2) y, al destruirse su unique_ptr, la forma se libera sola. std::sort ordena de mayor a menor área llamando a area(), que en cada forma ejecuta su propia versión. Las lambdas reciben const auto& porque un unique_ptr no se puede copiar.
El último bucle escribe cada forma y suma el área total: el banner (15), el logotipo (π · 1,5² ≈ 7,07) y el botón (3). Para ampliarlo, añada más tipos de forma: el resto del programa no cambia. En DMarlon Studio puede ejecutarlo con el destino Consola (F9) y, después, llevar estas mismas clases a una ventana de escritorio con FLTK.
Código · main.cpp
#include <algorithm>#include <iostream>#include <memory>#include <vector>struct Shape { // the interface every shape on the canvas follows const char* name; explicit Shape(const char* n) : name(n) {} virtual ~Shape() = default; virtual double area() const = 0;};struct Circle : Shape { double r; Circle(const char* n, double r) : Shape(n), r(r) {} double area() const override { return 3.14159 * r * r; }};struct Rect : Shape { double w, h; Rect(const char* n, double w, double h) : Shape(n), w(w), h(h) {} double area() const override { return w * h; }};int main() { std::vector<std::unique_ptr<Shape>> canvas; // the canvas owns its shapes canvas.push_back(std::make_unique<Rect>("banner", 6, 2.5)); canvas.push_back(std::make_unique<Circle>("logo", 1.5)); canvas.push_back(std::make_unique<Rect>("dot", 0.5, 0.4)); canvas.push_back(std::make_unique<Rect>("button", 3, 1)); canvas.erase(std::remove_if(canvas.begin(), canvas.end(), [](const auto& s) { return s->area() < 1; }), canvas.end()); std::sort(canvas.begin(), canvas.end(), [](const auto& a, const auto& b) { return a->area() > b->area(); }); double total = 0; for (const auto& s : canvas) { total += s->area(); std::cout << s->name << ": " << s->area() << "\n"; } std::cout << canvas.size() << " shapes, total area " << total << "\n";}Salida · c++ -std=c++17 main.cpp -o main && ./main
banner: 15 logo: 7.06858 button: 3 3 shapes, total area 25.0686
Para recordar
- Una interfaz abstracta y varias clases derivadas modelan las formas.
std::vector<std::unique_ptr<Base>>guarda objetos polimórficos y los libera solo.remove_if+eraseysortcon lambdas hacen el trabajo del editor.- Añadir una forma nueva no obliga a cambiar el código que las usa.
- Con RAII y punteros inteligentes no hace falta ningún
delete.
Ejercicio
Añada una clase Triangle (base y altura) con su área, ponga en el lienzo un triángulo «arrow» de 4 × 2,5 y, al final, escriba cuántas formas de cada tipo hay usando un std::map<std::string, int> y un método virtual kind().