What is Object Slicing in C++: Complete Explanation with Code
\n\nImagine a situation: you've written a beautiful class hierarchy, using polymorphism, everything works perfectly... And then a bug that's impossible to catch. Data just disappears. The object seems to "lose weight" right before your eyes. Sound familiar? Welcome to the world of object slicing — one of the most insidious pitfalls in C++.
\n\nIn this article, we'll break down what object slicing is, why it occurs, how to detect it, and most importantly, how to deal with it. You'll learn not only the theory but also see live code examples that will help you avoid this problem in your projects.
\n\nHow Inheritance Works and Why Slicing Occurs
\n\nFirst, let's recall how C++ manages memory with inheritance. When you create an object of a derived class, it contains a complete copy of the base class plus its own fields and methods.
\n\nclass 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\nA Dog object occupies more memory than an Animal. And this is where the root of the problem lies.
What Happens During Object Slicing
\n\nObject slicing is the loss of data that occurs when an object of a derived class is assigned to a variable of the base class by value. The compiler "cuts off" (slices) the part specific to the derived class, leaving only the base part.
\n\nClassic example:
\n\nDog myDog("Rex", 3, "Labrador");\nAnimal animal = myDog; // Here it is, slicing!\n\nstd::cout << animal.name << ", " << animal.age << std::endl;\n// animal.breed — not accessible!\n// animal.sound() will output "Some sound", not "Woof!"\n\nWhat happened here? We created a full-fledged dog with a name, age, and breed. But when assigning animal = myDog, the compiler only copied the part related to Animal. The breed field vanished without a trace. And the virtual function? It got "sliced" too — now the base class method is called.
Why Is This So Dangerous?
\n\nThe problem is that object slicing violates the principle of polymorphism. You think you're working with a dog, but in reality, you're working with an abstract animal. This leads to:
\n- \n
- Data loss (dog breed, car color, phone model — everything disappears) \n
- Incorrect behavior of virtual functions \n
- Hard-to-find bugs that are not caught at compile time \n
Slicing is especially insidious in containers. Look at this code:
\n\nstd::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(); // Always "Some sound"!\n}\n\nYou expect to hear barking and meowing, but you only get abstract sounds. The container std::vector<Animal> stores objects of exactly the Animal type, slicing off everything extra.
Detailed Breakdown: How Slicing Works Exactly
\n\nTo understand the mechanics, let's look at the sizes of the objects:
\n\nstd::cout << "Size of Animal: " << sizeof(Animal) << std::endl;\nstd::cout << "Size of Dog: " << sizeof(Dog) << std::endl;\n\n// Output (platform-dependent):\n// Size of Animal: 40\n// Size of Dog: 56\n\nWhen you write Animal animal = dog, the compiler calls the copy