对象切片会静默丢失派生类成员和虚函数重写,必须避免;应使用引用或指针传递、容器存智能指针、删除基类拷贝操作、提供虚clone()接口,并警惕隐式值传递场景。

对象切片不会报错,但会静默丢失派生类成员和虚函数重写——避免它不是“要不要做”,而是“必须做”的底线操作。
用引用或指针代替值传递
这是最直接、最常用、也最推荐的解法。只要你不创建新的基类对象,切片就无从发生。
-
void process(Animal a)→ 切片必然发生;改用void process(const Animal& a)或void process(Animal* a) - 引用绑定不触发拷贝构造,指针只是地址传递,二者都保留原始对象的完整类型信息和虚表指向
- 注意:
const Animal&不能调用非 const 成员函数;若需修改,用Animal&(确保传入的是非常量左值) - 容器中存指针或智能指针(如
std::vector<:unique_ptr>></:unique_ptr>),而非std::vector<animal></animal>
把基类拷贝/赋值操作设为 delete
让编译器在源头拦住错误写法,比靠人眼检查更可靠。
- 在基类中显式删除拷贝构造和拷贝赋值:
Animal(const Animal&) = delete;和Animal& operator=(const Animal&) = delete; - 这样
Animal a = dog;或a = dog;会直接编译失败,而不是静默切片 - 适用于你明确不希望基类被值语义使用的场景(比如所有多态类型都应通过指针/引用操作)
- 注意:这会让基类无法作为值类型存入某些容器(如
std::vector<animal></animal>),但本就是该避免的用法
需要克隆时,提供虚 clone() 接口
当业务逻辑确实需要“复制一个同类型的新对象”(比如原型模式),值拷贝不可替代,那就用虚函数控制拷贝行为。
立即学习“C++免费学习笔记(深入)”;
- 在基类声明纯虚函数:
virtual std::unique_ptr<animal> clone() const = 0;</animal> - 每个派生类实现自己的
clone(),返回std::unique_ptr<derived></derived>(可隐式转为std::unique_ptr<animal></animal>) - 调用
auto new_dog = dog.clone();得到的是完整 Dog 对象,不会切片 - 返回
std::unique_ptr比裸指针更安全,避免资源泄漏
最容易被忽略的一点是:切片常发生在看似“无害”的容器初始化或函数参数推导中,比如 std::make_shared<animal>(dog)</animal> 或 std::function<void> f = [](Animal a) { ... };</void> ——这些地方同样按值传参,一样切片。别只盯着显式的 = 赋值。


















