对象切片是派生类对象赋值给基类对象时仅保留基类部分、丢失派生成员与多态性的现象,因按类型大小内存拷贝且仅调用基类拷贝构造函数所致;应使用指针/引用、智能指针或禁用基类拷贝操作来避免。

对象切片是指将派生类对象赋值给基类对象(而非指针或引用)时,派生类中新增的成员和行为被“截掉”,只保留基类部分的现象。这会导致信息丢失,且无法多态调用派生类重写的虚函数。
为什么会发生对象切片?
根本原因是c++中对象赋值是按类型大小进行内存拷贝的。基类对象有固定大小,无法容纳派生类额外的数据成员;编译器只调用基类的拷贝构造函数或赋值运算符,跳过派生类部分。
常见触发场景包括:
- 用派生类对象直接初始化或赋值给基类对象(
Base b = Derived();) - 函数参数按值传递基类类型,却传入派生类对象(
void func(Base b); func(d);) - 容器存储基类对象(如
std::vector<base>),插入派生类实例
如何避免对象切片?
核心思路是不直接操作对象实体,而是通过间接方式保留类型信息和多态能力。
立即学习“C++免费学习笔记(深入)”;
- 用指针或引用代替值传递:函数参数、返回值、容器元素尽量使用
Base*或const Base&;现代C++推荐用std::unique_ptr<base>或std::shared_ptr<base>管理堆上派生对象 - 禁用基类的拷贝/赋值操作(可选):在基类中将拷贝构造函数和
operator=声明为delete,从语法层面阻止误用 - 避免值语义容器存多态对象:不要用
std::vector<base>存派生类对象;改用std::vector<:unique_ptr>></:unique_ptr>
一个典型错误与修正对比
错误写法:
class Base { public: virtual void say() { cout << "Base"; } }; class Derived : public Base { int x = 42; public: void say() override { cout << "Derived"; } }; <p>void bad_func(Base b) { b.say(); } // 切片发生,永远输出"Base" Base b = Derived(); // 切片发生,x丢失
正确写法:
void good_func(const Base& b) { b.say(); } // 输出"Derived" void good_func_ptr(const Base* b) { b->say(); } auto ptr = std::make_unique<Derived>(); good_func(*ptr); // 安全调用
基本上就这些。切片不是语法错误,但会悄悄破坏多态逻辑——关键在于养成用引用/智能指针代替值传递的习惯。