Qué es object slicing en C++: la desaparición secreta de datos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Qué es object slicing en C++: explicación completa con código

\n\n

Imagine una situación: ha escrito una hermosa jerarquía de clases, usa polimorfismo, todo funciona perfectamente… Y luego un error que es imposible de detectar. Los datos simplemente desaparecen. El objeto como si «adelgazara» ante sus ojos. ¿Le suena familiar? Bienvenido al mundo de object slicing (corte de objetos) — una de las trampas más engañosas de C++.

\n\n

En este artículo, analizaremos qué es object slicing, por qué ocurre, cómo detectarlo y, lo más importante, cómo combatirlo. Aprenderá no solo la teoría, sino que también verá ejemplos de código en vivo que le ayudarán a evitar este problema en sus proyectos.

\n\n

Cómo funciona la herencia y por qué ocurre el corte

\n\n

Para empezar, recordemos cómo C++ gestiona la memoria con la herencia. Cuando crea un objeto de una clase derivada, este contiene una copia completa de la clase base más sus propios campos y métodos.

\n\n
class Animal {\npublic:\n    std::string name;\n    int age;\n    Animal(const std::string& n, int a) : name(n), age(a) {}\n    virtual void sound() const { std::cout << "Some sound\\n"; }\n};\n\nclass Dog : public Animal {\npublic:\n    std::string breed;\n    Dog(const std::string& n, int a, const std::string& b) \n        : Animal(n, a), breed(b) {}\n    void sound() const override { std::cout << "Woof!\\n"; }\n};
\n\n

El objeto Dog ocupa más memoria que Animal. Y aquí es donde radica la raíz del problema.

\n\n

Qué sucede durante object slicing

\n\n

Object slicing (corte de objeto) es la pérdida de datos que ocurre cuando un objeto de una clase derivada se asigna a una variable de la clase base por valor. El compilador «corta» (rebana) la parte específica de la clase derivada, dejando solo la parte base.

\n\n

Ejemplo clásico:

\n\n
Dog myDog("Rex", 3, "Labrador");\nAnimal animal = myDog;  // ¡Aquí está el slicing!\n\nstd::cout << animal.name << ", " << animal.age << std::endl;\n// animal.breed — ¡no está disponible!\n// animal.sound() mostrará "Some sound", no "Woof!"
\n\n

¿Qué ocurrió aquí? Creamos un perro completo con nombre, edad y raza. Pero al asignar animal = myDog, el compilador copió solo la parte que pertenece a Animal. El campo breed desapareció sin dejar rastro. ¿Y la función virtual? También fue «cortada» — ahora se llama al método de la clase base.

\n\n

¿Por qué es tan peligroso?

\n\n

El problema es que object slicing viola el principio de polimorfismo. Piensa que está trabajando con un perro, pero en realidad lo hace con un animal abstracto. Esto conduce a:

\n
    \n
  • Pérdida de datos (raza del perro, color del coche, modelo del teléfono — todo desaparece)
  • \n
  • Funcionamiento incorrecto de las funciones virtuales
  • \n
  • Errores difíciles de detectar que no se capturan en la etapa de compilación
  • \n
\n\n

El slicing es particularmente engañoso en los contenedores. Observe este código:

\n\n
std::vector<Animal> zoo;\nzoo.push_back(Dog("Rex", 3, "Labrador"));\nzoo.push_back(Cat("Whiskers", 2, "Persian"));\n\nfor (const auto& animal : zoo) {\n    animal.sound();  // ¡Siempre "Some sound"!\n}
\n\n

Espera escuchar ladridos y maullidos, pero solo obtiene sonidos abstractos. El contenedor std::vector<Animal> almacena objetos exactamente del tipo Animal, cortando todo lo demás.

\n\n

Análisis detallado: cómo funciona exactamente el slicing

\n\n

Para entender la mecánica, veamos los tamaños de los objetos:

\n\n
std::cout << "Size of Animal: " << sizeof(Animal) << std::endl;\nstd::cout << "Size of Dog: " << sizeof(Dog) << std::endl;\n\n// Salida (depende de la plataforma):\n// Size of Animal: 40\n// Size of Dog: 56
\n\n

Cuando escribe Animal animal = dog, el compilador llama al constructor de copia de la clase base, ignorando los miembros adicionales de la clase derivada. Es como si tomara un molde para Animal y vertiera en él solo la parte correspondiente del objeto Dog.

Blogs

Book Recommendations