280 lines
8.5 KiB
Markdown
280 lines
8.5 KiB
Markdown
---
|
|
description: Refactoriza una clase C++ aplicando buenas prácticas de estilo
|
|
---
|
|
|
|
# Refactor Class Command
|
|
|
|
Refactoriza una clase C++ siguiendo estas reglas de estilo y buenas prácticas:
|
|
|
|
## Reglas de Refactorización
|
|
|
|
### 1. Inicialización de Variables Miembro
|
|
- **Inicializar en la declaración** todas las variables "simples" que no tengan dependencias complejas:
|
|
- Tipos primitivos: `int`, `float`, `bool`, etc.
|
|
- Enumeraciones: valores de enum class
|
|
- Valores por defecto conocidos: `0`, `0.0F`, `false`, `nullptr`, etc.
|
|
- **NO inicializar en declaración** si:
|
|
- Dependen de otros miembros
|
|
- Requieren llamadas a funciones complejas
|
|
- Son punteros a recursos que necesitan construcción específica
|
|
|
|
### 2. Structs con Valores por Defecto
|
|
- **Todos los miembros de structs** deben tener valores por defecto:
|
|
- Tipos primitivos: `int x{0}`, `float y{0.0F}`, `bool flag{false}`
|
|
- Strings: `std::string name{}`
|
|
- Punteros: `Type* ptr{nullptr}`
|
|
- **Ventajas**: Inicialización segura, evita valores indefinidos
|
|
|
|
### 3. Arrays C-style → std::array
|
|
- Convertir **todos** los arrays C-style a `std::array`:
|
|
- `Type array[N]` → `std::array<Type, N> array{}`
|
|
- Inicializar con `{}` para zero-initialization
|
|
- Agregar `#include <array>` si no existe
|
|
- **Ventajas**: type-safety, size(), métodos STL, sin decay a pointer
|
|
|
|
### 3. Reorganización de la Clase
|
|
|
|
#### Orden de Secciones
|
|
1. **public** (primero)
|
|
2. **private** (después)
|
|
|
|
#### Dentro de cada sección (private principalmente)
|
|
1. **Estructuras y enumeraciones** (tipos anidados)
|
|
2. **Constantes** (static constexpr)
|
|
3. **Métodos** (funciones miembro)
|
|
4. **Variables miembro** (al final)
|
|
|
|
### 4. Agrupación y Comentarios de Métodos
|
|
- **En sección public**: Agrupar métodos relacionados funcionalmente
|
|
- **Comentarios en línea** (a la derecha) para describir cada método/grupo
|
|
- **Formato**: `void method(); // Descripción concisa`
|
|
- **Espaciado**: Línea en blanco entre grupos funcionales
|
|
|
|
**Ejemplo:**
|
|
```cpp
|
|
public:
|
|
static void init(...); // Inicialización singleton
|
|
static void destroy(); // Destrucción singleton
|
|
static auto get() -> T*; // Acceso al singleton
|
|
|
|
void render(); // Renderizado
|
|
void update(float dt); // Actualización lógica
|
|
|
|
auto isActive() -> bool; // Consulta estado
|
|
```
|
|
|
|
### 5. Comentarios de Variables
|
|
- **Posición**: A la derecha de la variable/grupo
|
|
- **Formato**: `// Descripción concisa`
|
|
- Agrupar variables relacionadas con un comentario común
|
|
|
|
### 6. Constructores en Structs
|
|
- **Eliminar constructores por defecto redundantes** en structs:
|
|
- Si todos los miembros tienen inicialización en declaración
|
|
- Y no hay múltiples constructores
|
|
- Eliminar `explicit Type() = default;`
|
|
- El compilador generará automáticamente un constructor por defecto
|
|
|
|
**Ejemplo:**
|
|
```cpp
|
|
struct Data {
|
|
int x{0};
|
|
std::string name{};
|
|
// NO NECESITA: explicit Data() = default;
|
|
};
|
|
```
|
|
|
|
### 7. Includes Necesarios
|
|
- Agregar includes faltantes según lo que se use
|
|
- Mantener orden alfabético si es posible
|
|
|
|
### 8. Header Guards
|
|
- **Usar `#pragma once`** en todas las cabeceras (`.hpp`)
|
|
- **NO usar** `#ifndef`/`#define`/`#endif` tradicionales
|
|
- `#pragma once` debe ser la primera línea del archivo (antes de includes)
|
|
- **Ventajas**: Más simple, menos propenso a errores, ampliamente soportado
|
|
|
|
## Ejemplo de Aplicación
|
|
|
|
### Antes:
|
|
```cpp
|
|
class Example {
|
|
private:
|
|
struct Data {
|
|
std::string name;
|
|
int value;
|
|
};
|
|
|
|
int counter_;
|
|
bool flag_;
|
|
float values_[10];
|
|
|
|
public:
|
|
Example();
|
|
void update();
|
|
};
|
|
|
|
// Constructor
|
|
Example::Example()
|
|
: counter_(0),
|
|
flag_(false) {
|
|
for (int i = 0; i < 10; ++i) {
|
|
values_[i] = 0.0F;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Después:
|
|
```cpp
|
|
#pragma once
|
|
|
|
#include <array>
|
|
|
|
class Example {
|
|
public:
|
|
Example() = default; // Ya no necesita inicializar
|
|
void update();
|
|
|
|
private:
|
|
// Tipos anidados
|
|
struct Data {
|
|
std::string name{}; // Nombre con valor por defecto
|
|
int value{0}; // Valor inicializado
|
|
};
|
|
|
|
// Variables miembro
|
|
int counter_{0}; // Contador de frames
|
|
bool flag_{false}; // Estado activo
|
|
std::array<float, 10> values_{}; // Buffer de valores
|
|
};
|
|
```
|
|
|
|
## Tareas a Realizar
|
|
|
|
Cuando uses este comando en una clase específica:
|
|
|
|
1. **Leer** el archivo `.hpp` y `.cpp` correspondiente
|
|
2. **Verificar** que la cabecera use `#pragma once` (reemplazar `#ifndef`/`#define`/`#endif` si existen)
|
|
3. **Identificar** structs y agregar valores por defecto a todos sus miembros
|
|
4. **Identificar** variables que pueden inicializarse en declaración
|
|
5. **Identificar** arrays C-style que convertir a std::array
|
|
6. **Reorganizar** la estructura de la clase (public/private, agrupación)
|
|
7. **Actualizar** el archivo `.cpp` eliminando inicializaciones redundantes
|
|
8. **Compilar** para verificar sintaxis correcta
|
|
9. **Ejecutar clang-tidy** (análisis, sin --fix) y revisar resultados
|
|
10. **Ejecutar cppcheck** (nivel -w) y revisar resultados
|
|
11. **Aplicar fixes apropiados** basados en análisis de linters
|
|
12. **Recompilar** si se aplicaron fixes
|
|
13. **Reportar resumen** al usuario: cambios + hallazgos de linters
|
|
|
|
## Workflow de Linters (Pasos 9-12)
|
|
|
|
### Paso 9: Ejecutar clang-tidy
|
|
|
|
```bash
|
|
tools/linter/run_clang-tidy.sh archivo.cpp archivo.hpp
|
|
```
|
|
|
|
**Analizar resultados:**
|
|
- Identificar issues críticos (bugprone, cert)
|
|
- Separar recomendaciones válidas de falsos positivos
|
|
- Ignorar: magic-numbers en game constants, defaults.hpp errors
|
|
- Si hay issues críticos, informar al usuario y pausar
|
|
- Si solo hay recomendaciones, continuar
|
|
|
|
### Paso 10: Ejecutar cppcheck
|
|
|
|
```bash
|
|
tools/linter/run_cppcheck.sh -w --path archivo.cpp
|
|
```
|
|
|
|
**Leer archivo de resultados:**
|
|
- `tools/linter/cppcheck-result-warning-style-performance.txt`
|
|
- Identificar errores críticos (error, nullPointer, uninitvar)
|
|
- Separar warnings de style issues
|
|
- Filtrar falsos positivos (passedByValue para tipos pequeños, unusedFunction en API pública)
|
|
- Si hay errores críticos, informar al usuario y pausar
|
|
|
|
### Paso 11: Aplicar Fixes
|
|
|
|
**Si hay issues aplicables:**
|
|
|
|
1. **Fixes automáticos de clang-tidy** (solo si son seguros):
|
|
- modernize-use-auto
|
|
- readability-redundant-access-specifiers
|
|
- Performance optimizations claras
|
|
|
|
```bash
|
|
tools/linter/run_clang-tidy.sh --fix archivo.cpp archivo.hpp
|
|
```
|
|
|
|
2. **Fixes manuales necesarios:**
|
|
- Inicializar variables no inicializadas
|
|
- Corregir null pointer issues
|
|
- Resolver memory leaks
|
|
|
|
3. **Documentar cambios** para el reporte final
|
|
|
|
### Paso 12: Recompilar
|
|
|
|
Si se aplicaron fixes en paso 11:
|
|
|
|
```bash
|
|
cmake --build build
|
|
```
|
|
|
|
**Verificar:**
|
|
- ✅ Compilación exitosa → Continuar a reporte
|
|
- ❌ Errores → Informar al usuario, sugerir revisión manual
|
|
|
|
## Formato de Reporte Final (Paso 13)
|
|
|
|
```
|
|
=== Refactor Completado: ClassName ===
|
|
|
|
📝 Cambios estructurales:
|
|
✅ #pragma once aplicado
|
|
✅ 3 structs actualizados con valores por defecto
|
|
✅ 12 variables movidas a inicialización en declaración
|
|
✅ 2 arrays C-style → std::array
|
|
✅ Clase reorganizada (public primero, variables al final)
|
|
✅ Constructor simplificado (elimina 12 inicializaciones redundantes)
|
|
|
|
🔍 Análisis de linters:
|
|
|
|
clang-tidy:
|
|
✅ Sin issues críticos
|
|
🟡 3 recomendaciones aplicadas automáticamente:
|
|
- Modernize: use auto (2 lugares)
|
|
- Readability: redundant specifier (1 lugar)
|
|
⚪ 2 opcionales ignorados:
|
|
- magic-numbers en game constants
|
|
|
|
cppcheck:
|
|
✅ Sin errores
|
|
🟡 2 style issues encontrados:
|
|
- Unused variable 'temp' en línea 45 → Eliminada
|
|
- Redundant assignment en línea 102 → Corregida
|
|
|
|
📊 Resultado:
|
|
✅ Compilación exitosa
|
|
✅ Todos los linters pasan sin issues críticos
|
|
✅ Código refactorizado y verificado
|
|
|
|
💡 Próximos pasos:
|
|
- Revisar cambios manualmente
|
|
- Ejecutar tests si existen
|
|
- Commitear con mensaje descriptivo
|
|
```
|
|
|
|
## Notas Importantes
|
|
|
|
- **No cambiar lógica**: Solo refactorización estructural
|
|
- **Mantener compatibilidad**: std::array usa misma sintaxis [] para acceso
|
|
- **Formato consistente**: Respetar estilo del proyecto (comentarios, espaciado)
|
|
- **Validar compilación**: Siempre verificar que compile después de cambios
|
|
- **Linters integrados**: Análisis automático post-refactor para garantizar calidad
|
|
- **Fixes inteligentes**: Solo aplicar --fix de clang-tidy si los cambios son seguros
|
|
- **Contexto importa**: Game code tiene patrones legítimos (magic numbers, etc.)
|
|
- **Falsos positivos**: Identificar y documentar, no corregir ciegamente
|