DMarlon Studio

Lección 16 · 16 de 20

Espacios de nombres y enum class · C++

Organice el código de C++ con namespaces, alias y using, y use enum class para estados con nombre y seguros: los pasos de un pedido.

C++ · Espacios de nombres y enum class en DMarlon Studio: el código del ejemplo y su salida en la terminal

Un espacio de nombres (namespace) agrupa nombres para que no choquen con los de otras partes del programa o de otras bibliotecas: shop::label no se confunde con ningún otro label. Es lo que hace std:: con toda la biblioteca estándar. Desde fuera se usa el nombre completo, con ::.

Desde C++17, namespace shop::tax abre un espacio anidado en una sola línea, y namespace tx = shop::tax; crea un alias más corto. using shop::OrderStatus; trae solo ese nombre al bloque de main, que es más prudente que traer un espacio entero con using namespace.

`enum class` define un tipo con valores con nombre. A diferencia del enum clásico, sus nombres van dentro del tipo (OrderStatus::Paid) y no se convierten solos en enteros: status == 2 no compilaría. Para pasar al paso siguiente hay que convertir a propósito, con static_cast<int> y de vuelta con static_cast<OrderStatus>; los valores empiezan en 0, así que «shipped» es el paso 2.

También se puede elegir el tipo subyacente: Priority : char guarda cada valor en un carácter, 'L' o 'H'. El switch de label cubre todos los estados; si se añade uno nuevo y se olvida aquí, -Wall avisa. constexpr double vat es una constante que el compilador conoce de antemano, como verá en la lección 19.

Código · main.cpp

#include <iostream>#include <string>namespace shop {    // enum class: scoped names that do not turn into int on their own.    enum class OrderStatus { Pending, Paid, Shipped, Delivered };    enum class Priority : char { Low = 'L', High = 'H' };    // chosen underlying type    std::string label(OrderStatus s) {        switch (s) {            case OrderStatus::Pending:   return "pending";            case OrderStatus::Paid:      return "paid";            case OrderStatus::Shipped:   return "shipped";            case OrderStatus::Delivered: return "delivered";        }        return "unknown";    }}namespace shop::tax {                  // a nested namespace (C++17 syntax)    constexpr double vat = 0.21;    double withVat(double net) { return net * (1 + vat); }}namespace tx = shop::tax;              // a shorter aliasint main() {    using shop::OrderStatus;           // bring in just this one name    OrderStatus status = OrderStatus::Paid;    std::cout << "Order is " << shop::label(status) << "\n";    status = static_cast<OrderStatus>(static_cast<int>(status) + 1);    // next step    std::cout << "Now it is " << shop::label(status) << " (step " << static_cast<int>(status) << ")\n";    std::cout << "Priority code: " << static_cast<char>(shop::Priority::High) << "\n";    std::cout << "120 EUR + VAT = " << tx::withVat(120) << " EUR\n";}

Salida · c++ -std=c++17 main.cpp -o main && ./main

Order is paid
Now it is shipped (step 2)
Priority code: H
120 EUR + VAT = 145.2 EUR

Para recordar

  • namespace nombre { ... } agrupa código; se usa como nombre::cosa.
  • namespace a::b anida y namespace x = a::b; crea un alias.
  • using a::cosa; trae un solo nombre; evite using namespace en cabeceras.
  • enum class no se mezcla con enteros sin un static_cast.
  • enum class E : char elige el tipo con el que se guarda.

Ejercicio

Añada el estado Cancelled a OrderStatus, compile para ver el aviso del switch y complete label para que devuelva "cancelled".