对象切片是指派生类对象赋值给基类对象时,仅保留基类部分而丢失派生类成员的现象。1. 值传递引发切片:当Dog对象以值方式传入Animal参数时,仅复制基类部分,导致多态失效;2. 指针避免切片:通过Animal*指向Dog对象,调用speak()可正确执行派生类函数;3. 引用避免切片:使用const Animal&传参,不复制对象,保持多态行为;4. 容器应存指针:vector保存派生类对象,避免复制导致的切片;5. 多态依赖指针或引用:虚函数动态绑定仅在指针或引用调用时生效,值传递则静态绑定至基类。因此,实现多态必须使用指针或引用,避免值传递。

在c++中,对象切片(Object Slicing)是指当一个派生类对象被赋值给基类对象时,派生类中新增的成员变量和函数被“切掉”,只保留基类部分的现象。这通常发生在值传递过程中,会导致多态行为失效,是面向对象编程中的常见陷阱。
什么是对象切片?
假设你有一个基类 Animal 和一个派生类 Dog:
class Animal { public: virtual void speak() { cout << "Animal speaksn"; } }; <p>class Dog : public Animal { public: void speak() override { cout << "Dog barksn"; } void wagTail() { cout << "Tail waggingn"; } };</p>
如果你这样写代码:
Dog dog; Animal animal = dog; // 对象切片发生 animal.speak(); // 输出: Animal speaks(不是期望的 Dog barks)
此时,dog 被复制为 Animal 类型对象,其 wagTail() 成员和重写的 speak() 行为都丢失了,这就是对象切片。
立即学习“C++免费学习笔记(深入)”;
如何避免对象切片?
关键在于:使用指针或引用传递对象,而不是值传递。这样才能保留多态性。
1. 使用基类指针
Dog dog; Animal* ptr = &dog; ptr->speak(); // 正确输出: Dog barks
指针指向派生类对象,调用的是实际对象的虚函数,不会发生切片。
2. 使用基类引用
void makeSound(const Animal& animal) { animal.speak(); // 多态调用 } <p>Dog dog; makeSound(dog); // 输出: Dog barks,无切片</p>
引用不会复制对象,因此完整保留派生类信息。
3. 容器中存储指针或智能指针
若需在容器中保存多种类型对象,不要使用 vector
vector<unique_ptr<Animal>> animals; animals.push_back(make_unique<Dog>()); animals.push_back(make_unique<Cat>()); <p>for (auto& animal : animals) animal->speak(); // 各自调用正确的 speak()</p>
这样每个对象都以指针形式保存,避免复制导致的切片。
多态与指针/引用的重要性
C++的多态依赖于虚函数表和动态绑定,而动态绑定只在通过指针或引用调用虚函数时生效。值传递会直接构造基类对象,无法访问派生类的虚表,因此多态失效。
指针和引用不仅避免了对象切片,还提高了性能(避免不必要的拷贝),是实现运行时多态的必要手段。
基本上就这些。只要记住:想用多态,就别传值,用指针或引用。不复杂但容易忽略。