Historia de la pregunta:
C++ se construyó sobre la base de C, que proporcionó un pequeño conjunto de tipos incorporados: números, caracteres, arreglos. Con el desarrollo del lenguaje, aparecieron conceptos como estructuras, clases, enumeraciones, que se convirtieron en tipos definidos por el usuario.
Problema:
El tipo de dato en un programa define cuánta memoria ocupará una variable, cómo será inicializada, copiada, destruida y comparada. Los tipos incorporados tienen un comportamiento definido por el estándar, los tipos definidos por el usuario requieren una descripción explícita de todos los aspectos. Los errores en la gestión de tipos definidos por el usuario pueden llevar a fallos, filtraciones, comparaciones injustas de objetos, etc.
Solución:
Los tipos incorporados son int, float, double, char, bool y otros "primitivos". Los tipos definidos por el usuario son cualquier estructura, clase, unión creada por ti. Para tareas complejas, es necesario implementar tipos definidos por el usuario con una semántica adecuada de copia, comparación y gestión de recursos.
Ejemplo de código:
// Tipo incorporado int x = 5; // Tipo definido por el usuario struct Point { double x, y; }; Point a = {1.0, 2.0}; // Clase con recursos class MyFile { public: MyFile(const std::string& fn) : f(fopen(fn.c_str(), "r")) {} ~MyFile() { if (f) fclose(f); } private: FILE* f; };
¿Pueden los tipos definidos por el usuario comportarse completamente como tipos incorporados (por ejemplo, compararse a través de == "por defecto")?
No, la comparación == funciona por defecto solo a partir de C++20 a través de defaulted operator==, antes de eso se necesitaba una definición explícita.
¿Se puede omitir la implementación del constructor de copia y del destructor, si la clase solo mantiene un puntero crudo (int, FILE, etc.)?**
No, en este caso, por defecto, la copia será "superficial", lo que provocará filtraciones o liberaciones dobles de memoria/recurso. Se debe implementar la "Regla de los Cinco".
¿Se inicializa el valor de la estructura por defecto a ceros (Point p;)?
No, una estructura local puede no estar inicializada, y el contenido de la memoria es aleatorio. Usar inicialización explícita.
Caso negativo:
Una clase envoltura sobre un archivo no implementó el destructor. El programa funcionaba, hasta que comenzó a procesar miles de archivos sin cerrar los descriptores.
Ventajas: menos código, aspecto simplificado. Desventajas: filtraciones de recursos, comportamiento inestable.
Caso positivo:
La clase implementa RAII: el archivo se abre en el constructor, se cierra en el destructor, se prohíbe la copia.
Ventajas: fiabilidad, seguridad, interfaz limpia. Desventajas: necesidad de recordar la "regla de cinco" y escribir más código.