C++ Slicing Problem | 'Object Got Sliced' Inheritance Copy Error Solution

C++ Slicing Problem | 'Object Got Sliced' Inheritance Copy Error Solution

이 글의 핵심

C++ slicing problem C++, slicing, "object, Introduction: "Copied derived class but data disappeared" explained in detail with practical examples.

Introduction: “Copied Derived Class but Data Disappeared"

"Polymorphism Not Working”

In C++, when copying derived class object to base class type, derived class members get sliced off causing slicing problem.

// ❌ Slicing problem
class Animal {
public:
    virtual void speak() {
        std::cout << "Animal sound\n";
    }
};

class Dog : public Animal {
    std::string name_;
public:
    Dog(const std::string& name) : name_(name) {}
    
    void speak() override {
        std::cout << name_ << " barks\n";
    }
};

void makeSound(Animal animal) {  // ❌ Pass by value
    animal.speak();
}

int main() {
    Dog dog("Buddy");
    makeSound(dog);  // ❌ Slicing occurs
    // Output: Animal sound (Dog got sliced!)
}

What This Guide Covers:

  • What is slicing problem?
  • Polymorphism loss
  • Solution with reference/pointer
  • Copy prevention pattern

1. What is Slicing Problem?

Slicing Occurs

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

class Base {
public:
    int x = 1;
    virtual void foo() {
        std::cout << "Base::foo\n";
    }
};

class Derived : public Base {
public:
    int y = 2;  // Derived class member
    void foo() override {
        std::cout << "Derived::foo\n";
    }
};

int main() {
    Derived d;
    Base b = d;  // ❌ Slicing occurs
    
    std::cout << b.x << '\n';  // 1
    // std::cout << b.y << '\n';  // Compile error: no y
    
    b.foo();  // Base::foo (polymorphism lost)
}

Problems:

  • y member lost
  • Polymorphism lost (virtual ignored)
  • vtable pointer not copied

2. Polymorphism Loss

Example 1: Function Argument

Below is an implementation example using C++. Understand the role of each part while examining the code.

// ❌ Pass by value
void process(Animal animal) {  // Slicing
    animal.speak();  // Animal::speak called
}

Dog dog("Buddy");
process(dog);  // Animal sound (polymorphism lost)

// ✅ Pass by reference
void process(Animal& animal) {  // No slicing
    animal.speak();  // Dog::speak called
}

process(dog);  // Buddy barks (polymorphism preserved)

Example 2: Container

Below is an implementation example using C++. Try running the code directly to check its operation.

// ❌ vector<Base>
std::vector<Animal> animals;
animals.push_back(Dog("Buddy"));  // Slicing
animals[0].speak();  // Animal sound

// ✅ vector<unique_ptr<Base>>
std::vector<std::unique_ptr<Animal>> animals;
animals.push_back(std::make_unique<Dog>("Buddy"));
animals[0]->speak();  // Buddy barks

3. Solution: Reference/Pointer

Solution 1: Use Reference

Below is an implementation example using C++. Try running the code directly to check its operation.

// ✅ Reference
void process(const Animal& animal) {
    animal.speak();
}

Dog dog("Buddy");
process(dog);  // Buddy barks

Solution 2: Use Pointer

Below is an implementation example using C++. Perform branching with conditionals. Try running the code directly to check its operation.

// ✅ Pointer
void process(Animal* animal) {
    if (animal) {
        animal->speak();
    }
}

Dog dog("Buddy");
process(&dog);  // Buddy barks

Solution 3: Smart Pointer

Below is an implementation example using C++. Understand the role of each part while examining the code.

// ✅ unique_ptr
void process(std::unique_ptr<Animal> animal) {
    animal->speak();
}

process(std::make_unique<Dog>("Buddy"));  // Buddy barks

// ✅ shared_ptr
void process(std::shared_ptr<Animal> animal) {
    animal->speak();
}

process(std::make_shared<Dog>("Buddy"));  // Buddy barks

4. Copy Prevention Pattern

Pattern 1: Delete Copy Constructor

Here is detailed implementation code using C++. Define a class to encapsulate data and functionality. Understand the role of each part while examining the code.

class Animal {
public:
    Animal() = default;
    Animal(const Animal&) = delete;  // Prevent copy
    Animal& operator=(const Animal&) = delete;
    
    virtual ~Animal() = default;
    virtual void speak() = 0;
};

class Dog : public Animal {
public:
    void speak() override {
        std::cout << "Bark\n";
    }
};

int main() {
    Dog dog;
    // Animal a = dog;  // Compile error
}

Summary

Key Points

  1. Slicing: Derived members lost when copying to base type
  2. Polymorphism loss: Virtual functions ignored
  3. Solution: Use reference or pointer
  4. Prevention: Delete copy constructor
  5. Container: Store pointers, not objects

When to Use

Prevent slicing by:

  • Using reference/pointer
  • Deleting copy constructor
  • Using smart pointers
  • Storing pointers in containers

Don’t:

  • Pass polymorphic objects by value
  • Store polymorphic objects directly in containers
  • Copy derived to base type

Best Practices

  • ✅ Always use reference/pointer for polymorphism
  • ✅ Delete copy constructor in base class
  • ✅ Use smart pointers for ownership
  • ❌ Don’t pass polymorphic objects by value
  • ❌ Don’t store objects in vector

Master slicing prevention for safer C++ polymorphism! 🚀