Struct vs Class
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 37 de 104.
En C++, struct y class son casi idénticos. Ambos pueden tener variables miembro, funciones miembro, constructores y admiten herencia. La única diferencia es su nivel de acceso predeterminado.
En una class, los miembros son privados por defecto. En una struct, los miembros son públicos por defecto:
struct Point {
int x; // público por defecto
int y; // público por defecto
};
class Circle {
double radius; // privado por defecto
public:
double getRadius() { return radius; }
};Esto también se aplica a la herencia. Una struct hereda públicamente por defecto, mientras que una class hereda privadamente:
struct DerivedStruct : Base {}; // herencia pública
class DerivedClass : Base {}; // herencia privadaMás allá de estos valores predeterminados, no hay ninguna diferencia técnica. Sin embargo, la convención importa.
La mayoría de los programadores de C++ utilizan struct para contenedores de datos simples con miembros públicos (como una coordenada o configuración), y class cuando la encapsulación y el comportamiento son importantes. Seguir esta convención hace que la intención de su código sea más clara para otros desarrolladores.
Desafío
FácilVamos a construir un sistema de configuración simple que demuestre cuándo usar struct frente a class basándonos en las convenciones de C++. Crearás un struct para datos simples que deben ser accesibles abiertamente, y una class para datos que requieren encapsulación y acceso controlado.
Crearás dos archivos para organizar tu código:
Config.h: Define tanto una estructura como una clase que representen diferentes tipos de datos de configuración.Primero, crea un
structllamadoDimensions— un contenedor de datos simple para el ancho (width) y el alto (height) (ambosint). Dado que los structs tienen miembros públicos por defecto, estos deben ser directamente accesibles sin getters. Incluye un métodoarea()que devuelva el producto del ancho y el alto.Luego, crea una
classllamadaAppConfigque gestione la configuración de la aplicación con la encapsulación adecuada. Debe almacenar un nombre de aplicación (string) y un objetoDimensionspara el tamaño de la ventana. Dado que los miembros de la clase son privados por defecto, deberás hacer explícitamente accesible tu interfaz pública. Proporciona:- Un constructor que reciba el nombre de la aplicación, el ancho y el alto
- Un getter
getAppName()que devuelva el nombre - Un getter
getWindowSize()que devuelva lasDimensions - Un método
displayConfig()que imprima:"App: <name>, Window: <width>x<height>, Area: <area>"
main.cpp: Demuestra la diferencia entre el uso de struct y class. Lee un nombre de aplicación, un ancho y un alto de la entrada (tres líneas separadas), luego:- Crea un
structDimensionsdirectamente con los valores de ancho y alto — accede a sus miembros directamente para imprimir:"Direct struct access: <width> x <height>" - Crea un objeto
AppConfigcon los tres valores - Llama a
displayConfig()para mostrar la configuración completa - Usa el getter para recuperar las dimensiones de la ventana e imprime:
"Via getter - Area: <area>"
- Crea un
Este desafío resalta la convención: usa struct cuando tengas datos simples y transparentes (como coordenadas o dimensiones), y usa class cuando quieras controlar el acceso y añadir comportamiento alrededor de tus datos.
Convierte las entradas de ancho y alto de strings a enteros usando std::stoi(). No olvides los header guards en tu archivo de cabecera.
Hoja de referencia
En C++, struct y class son casi idénticos, con una diferencia clave: su nivel de acceso predeterminado.
En un struct, los miembros son públicos por defecto:
struct Point {
int x; // público por defecto
int y; // público por defecto
};En una class, los miembros son privados por defecto:
class Circle {
double radius; // privado por defecto
public:
double getRadius() { return radius; }
};Esto también se aplica a la herencia:
struct DerivedStruct : Base {}; // herencia pública por defecto
class DerivedClass : Base {}; // herencia privada por defectoConvención: Usa struct para contenedores de datos simples con miembros públicos, y class cuando la encapsulación y el comportamiento sean importantes.
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "Config.h"
using namespace std;
int main() {
// Leer entrada
string appName;
string widthStr;
string heightStr;
getline(cin, appName);
getline(cin, widthStr);
getline(cin, heightStr);
int width = stoi(widthStr);
int height = stoi(heightStr);
// TODO: Crear un struct Dimensions con width y height
// Acceder a sus miembros directamente para imprimir: "Direct struct access: <width> x <height>"
// TODO: Crear un objeto AppConfig con appName, width y height
// TODO: Llamar a displayConfig() en el objeto AppConfig
// TODO: Usar el getter getWindowSize() para obtener las dimensiones e imprimir: "Via getter - Area: <area>"
return 0;
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosConstrucción y compilación en C++Archivos de cabecera y archivos fuenteNamespaces y alcanceIntroducción a OOP en C++Clases vs ObjetosEl puntero 'this'Métodos (Funciones miembro)Atributos (Miembros de datos)Conceptos básicos de Ctors y DtorsResumen - Calculadora simple4Propiedades de clase
Miembros de instancia vs. estáticosGetters y SettersFunciones miembro constPalabra clave mutableMétodos y variables estáticosFunciones y clases amigasResumen - Gestor de cuentas bancarias7Herencia
Herencia básicaNiveles de acceso en la herenciaOrden de llamada de Ctor y DtorSobrescritura de métodosFunciones virtuales y VTableHerencia múltipleHerencia virtualResumen - Jerarquía de empleados2Gestión de memoria
Memoria Stack vs HeapPunteros y referenciasMemoria dinámica (new/delete)Punteros inteligentes en C++RAII en C++Resumen - Gestor de arrays dinámicos5Encapsulamiento
Especificadores de acceso en C++Especificadores de acceso en profundidadOcultamiento de informaciónStruct vs ClassClases anidadas e internasResumen - Sistema de registros de estudiantes8Polimorfismo
Polimorfismo: Compilación vs. Tiempo de ejecuciónSobrecarga de funcionesFunciones virtuales revisadasFunciones virtuales purasClases abstractasDiseño de interfaces en C++Dynamic Casting y RTTIResumen: Calculadora de figuras11Conceptos avanzados de POO
Composición vs. HerenciaMixins mediante CRTPIdioma PimplBorrado de tiposEnum Classes y tipado fuerteManejo de excepciones en POOJerarquías de excepciones personalizadas14Patrones de diseño - Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositeRAII como patrón3Constructores y Destructores
Constructor por defectoConstructor parametrizadoConstructor de copiaConstructor de movimientoListas de inicialización del constructorConstructores delegadosAnálisis profundo del destructorRegla de tres / cinco / ceroResumen - Clase String6Sobrecarga de operadores
Introducción a la sobrecarga de operadoresSobrecarga de operadores aritméticosSobrecarga de operadores de comparaciónOperadores de flujo (Stream)Sobrecarga del operador de asignaciónSobrecarga de los operadores [] y ()Operadores de conversión de tiposResumen - Clase Matrix9Plantillas
Plantillas de funcionesPlantillas de clasesEspecialización de plantillasPlantillas variádicasConceptos básicos de SFINAE y Type TraitsResumen - Contenedor genérico