[2026] C++ Object Slicing: Value Copies, Polymorphism, and Fixes

[2026] C++ Object Slicing: Value Copies, Polymorphism, and Fixes

이 글의 핵심

Object slicing in C++: copying derived objects into base values loses state and breaks virtual dispatch—use references, pointers, and smart pointers.

What is object slicing?

When you put a derived object into a base object by value, only the base subobject is copied; members and polymorphic behavior that belong only to Derived are cut off—like slicing a loaf of bread.

Why it happens (memory view)

In Base b = d;, the left-hand side is type Base, so the compiler only allocates sizeof(Base). The assignment copies the base part of d. Fields that exist only in Derived (e.g. y below) have no storage in b. 다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 타입 정의
class Base {
    int x;   // part of Base layout
};
class Derived : public Base {
    int y;   // extra member after Base
};
Derived d;
d.x = 1;
d.y = 2;
Base b = d;  // only x is meaningfully copied; y is sliced
// b’s static type is Base, so b.y is ill-formed

Why virtual dispatch “breaks” follows the same idea: by value, the live object is a base-sized copy, so calls may resolve like the base type (see example 1).

Causes

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// 1. Pass by value
void func(Base b) {  // slicing
    // ...
}
Derived d;
func(d);
// 2. Return by value
Base func() {
    Derived d;
    return d;  // slicing
}
// 3. Containers
std::vector<Base> vec;
Derived d;
vec.push_back(d);  // slicing

Practical examples

Example 1: The bug

다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Animal {
public:
    virtual void speak() {
        std::cout << "Animal" << std::endl;
    }
};
class Dog : public Animal {
public:
    void speak() override {
        std::cout << "Woof!" << std::endl;
    }
};
void makeSpeak(Animal a) {  // by value
    a.speak();  // always "Animal"
}
int main() {
    Dog d;
    makeSpeak(d);  // "Animal" (slicing)
}

Example 2: Correct fix

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Reference
void makeSpeak(Animal& a) {
    a.speak();  // polymorphism works
}
// Pointer
void makeSpeak(Animal* a) {
    a->speak();  // polymorphism works
}
int main() {
    Dog d;
    makeSpeak(d);   // "Woof!"
    makeSpeak(&d);  // "Woof!"
}

Example 3: Containers

다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

// Bad: value container
std::vector<Animal> animals;
Dog d;
animals.push_back(d);  // slicing
animals[0].speak();    // "Animal"
// Pointer container
std::vector<Animal*> animals;
Dog* d = new Dog();
animals.push_back(d);
animals[0]->speak();   // "Woof!"
// Smart pointers
std::vector<std::unique_ptr<Animal>> animals;
animals.push_back(std::make_unique<Dog>());
animals[0]->speak();   // "Woof!"

Example 4: Preventing copy

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

class Base {
public:
    virtual ~Base() = default;
    
    Base(const Base&) = delete;
    Base& operator=(const Base&) = delete;
    
    Base(Base&&) = default;
    Base& operator=(Base&&) = default;
    
protected:
    Base() = default;
};

Common pitfalls

Pitfall 1: Pass by value

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Bad
void process(Base obj) {
    obj.virtualFunc();  // slicing
}
// Good
void process(const Base& obj) {
    obj.virtualFunc();  // polymorphism
}

Pitfall 2: Return by value

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Bad
Base create() {
    return Derived();  // slicing
}
// Good
std::unique_ptr<Base> create() {
    return std::make_unique<Derived>();
}

Pitfall 3: Assignment

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

Derived d;
Base b;
b = d;  // slicing
// Pointer keeps dynamic type
Base* b = &d;  // polymorphism preserved

Pitfall 4: Storing in vectors by value

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Bad
std::vector<Base> vec;
vec.push_back(Derived());  // slicing
// Good
std::vector<std::unique_ptr<Base>> vec;
vec.push_back(std::make_unique<Derived>());

Detection

아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.

// Compiler warnings
g++ -Weffc++ program.cpp
// Delete copy ctor
class Base {
public:
    Base() = default;
    Base(const Base&) = delete;  // prevent slicing
};

FAQ

Q1: When does slicing happen?

A: When a derived object is copied into a base by value.

Q2: Fixes?

A:

  • References
  • Pointers
  • Smart pointers

Q3: How to detect?

A:

  • Compiler warnings
  • Deleted copy operations

Q4: Performance?

A: References and pointers add no slicing issue.

Q5: Containers?

A: Prefer smart-pointer containers for polymorphic types.

Q6: Learning resources?

A:

  • Effective C++
  • C++ Primer
  • More Effective C++

Practical tips

Debugging

  • Check warnings first
  • Reproduce minimally

Performance

  • Profile before tuning

Code review

  • Follow conventions

Practical checklist

Before coding

  • Right technique for the problem?
  • Team can maintain it?
  • Meets performance goals?

While coding

  • Warnings clean?
  • Edge cases?
  • Error handling?

At review

  • Intent clear?
  • Tests enough?
  • Documented?

Keywords

C++, object slicing, polymorphism, inheritance, value semantics

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3