Miembros de instancia vs. estáticos
Parte de la sección Programación Orientada a Objetos del Journey de C++ de Coddy — lección 27 de 104.
Hasta ahora, cada variable miembro que has creado pertenece a un objeto específico. Cuando creas dos objetos Player, cada uno tiene su propio name y health. Estos se denominan miembros de instancia; existen por separado para cada instancia de la clase.
¿Pero qué pasa si necesitas datos compartidos entre todos los objetos? Por ejemplo, rastrear cuántos jugadores existen en total.
Aquí es donde entran en juego los miembros estáticos. Un miembro estático pertenece a la clase misma, no a ningún objeto en particular.
class Player {
std::string name; // Miembro de instancia - cada jugador tiene el suyo propio
int health; // Miembro de instancia
static int playerCount; // Miembro estático - compartido por TODOS los jugadores
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Incrementar cuando se crea cualquier jugador
}
~Player() {
playerCount--; // Decrementar cuando se destruye cualquier jugador
}
};La diferencia clave: los miembros de instancia se acceden a través de un objeto, mientras que los miembros estáticos se pueden acceder a través del propio nombre de la clase. Piense en los miembros de instancia como "uno por objeto" y en los miembros estáticos como "uno por clase".
| Miembros de instancia | Miembros estáticos |
|---|---|
| Únicos para cada objeto | Compartidos entre todos los objetos |
| Creados cuando se crea el objeto | Existen antes de que se cree cualquier objeto |
Accedidos a través del objeto: player.health | Accedidos a través de la clase: Player::playerCount |
Los miembros estáticos son útiles para contadores, valores de configuración o cualquier dato que pertenezca lógicamente a la clase en lugar de a objetos individuales.
Desafío
FácilConstruyamos un sistema de inventario de productos que rastree tanto los detalles individuales de los productos como las estadísticas generales del inventario utilizando miembros de instancia y estáticos.
Crearás dos archivos para organizar tu código:
Product.h: Define una claseProductque gestione productos individuales mientras también rastrea los datos de todo el inventario. Tu clase debe tener:- Miembros de instancia:
name(string) yprice(double) — únicos para cada producto - Un miembro estático
totalProductsque cuente cuántos productos existen actualmente - Un miembro estático
totalValueque rastree el precio combinado de todos los productos - Un constructor que reciba un nombre y un precio, inicialice los miembros de instancia y actualice ambos contadores estáticos (incrementar la cuenta, sumar el precio al valor total)
- Un destructor que actualice los contadores estáticos cuando se elimine un producto (decrementar la cuenta, restar el precio del valor total)
- Un método
getInfo()que devuelva un string en el formato:"<name>: "<name>: $<price>"lt;price>" - Un método estático
getInventoryStats()que devuelva un string:"Products: <count>, Total Value: "Products: <count>, Total Value: $<value>"lt;value>"
- Miembros de instancia:
main.cpp: Demuestra cómo los miembros estáticos se comparten entre todos los objetos mientras que los miembros de instancia permanecen únicos. Lee dos nombres de productos y sus precios desde la entrada (name1, price1, name2, price2 — cada uno en una línea separada), luego:- Imprime las estadísticas iniciales del inventario usando el nombre de la clase:
Product::getInventoryStats() - Crea un bloque de alcance con llaves y dentro de él crea un
Productcon el primer nombre y precio. Imprime su información y las estadísticas actuales del inventario. - Después de que termine el bloque (el primer producto es destruido), imprime
"After first scope:"seguido de las estadísticas del inventario - Crea otro
Productcon el segundo nombre y precio. Imprime su información y las estadísticas del inventario. - Crea un tercer
Productcon el nombre"Bonus"y el precio5.00. Imprime las estadísticas finales del inventario.
- Imprime las estadísticas iniciales del inventario usando el nombre de la clase:
Recuerda definir tus miembros estáticos fuera de la clase en el archivo de cabecera (después de la definición de la clase). Formatea los precios con dos decimales usando std::fixed y std::setprecision(2) de <iomanip>.
Incluye tu archivo de cabecera en main.cpp usando #include "Product.h".
Hoja de referencia
C++ admite dos tipos de miembros de clase: miembros de instancia y miembros estáticos.
Los miembros de instancia son únicos para cada objeto: cada instancia tiene su propia copia:
class Player {
std::string name; // Cada jugador tiene su propio nombre
int health; // Cada jugador tiene su propia salud
};Los miembros estáticos se comparten entre todos los objetos de una clase; solo hay una copia que pertenece a la clase misma:
class Player {
static int playerCount; // Compartido por TODOS los jugadores
public:
Player(std::string n) : name(n), health(100) {
playerCount++; // Incrementar el contador compartido
}
~Player() {
playerCount--; // Decrementar cuando se destruye
}
};Diferencias clave:
| Miembros de instancia | Miembros estáticos |
|---|---|
| Únicos para cada objeto | Compartidos entre todos los objetos |
| Creados cuando se crea el objeto | Existen antes de que se cree cualquier objeto |
Se accede a través del objeto: player.health | Se accede a través de la clase: Player::playerCount |
Los métodos estáticos se pueden llamar usando el nombre de la clase y solo pueden acceder a miembros estáticos:
class Player {
static int playerCount;
public:
static int getPlayerCount() {
return playerCount; // Solo puede acceder a miembros estáticos
}
};
// Llamar usando el nombre de la clase
int count = Player::getPlayerCount();Los miembros estáticos deben definirse fuera de la clase (normalmente en un archivo .cpp o después de la definición de la clase en un encabezado):
int Player::playerCount = 0;Los miembros estáticos son útiles para contadores, valores de configuración compartidos o cualquier dato que pertenezca lógicamente a la clase en lugar de a los objetos individuales.
Pruébalo tú mismo
#include <iostream>
#include <string>
#include "Product.h"
using namespace std;
int main() {
// Leer entrada
string name1;
double price1;
string name2;
double price2;
getline(cin, name1);
cin >> price1;
cin.ignore();
getline(cin, name2);
cin >> price2;
// TODO: Imprimir las estadísticas iniciales del inventario usando Product::getInventoryStats()
// TODO: Crear un bloque de alcance con llaves
// Dentro del bloque:
// - Crear un Product con name1 y price1
// - Imprimir su información usando getInfo()
// - Imprimir las estadísticas actuales del inventario
// TODO: Después de que termine el bloque, imprimir "After first scope:"
// Luego imprimir las estadísticas del inventario
// TODO: Crear otro Product con name2 y price2
// Imprimir su información y las estadísticas del inventario
// TODO: Crear un tercer Product con el nombre "Bonus" y el precio 5.00
// Imprimir las estadísticas finales del inventario
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