C++中派生类对象作为基类参数传递时无法调用重写函数的问题
对象切片导致多态失效的问题分析与解决
你遇到的核心问题是对象切片(Object Slicing),这是C++中按值传递派生类对象到基类参数时的典型问题,具体原因和解决方法如下:
问题根源
你的setDevice函数参数是按值传递的Device device:
void XYZ::setDevice(int num, Device device)
当你传入InputDevice对象时,编译器会创建一个基类Device的副本——只保留基类的成员变量和虚函数表,派生类特有的成员、重写的虚函数实现都会被“切掉”。这就导致:
- 后续无法访问派生类专属函数,因为这些成员已经不存在了
- 调用虚函数时执行基类版本,动态绑定完全失效
- 你的代码里
typeid(device).name()打印Device,就是因为参数已经被切片成了纯基类对象
解决方案
要保留多态特性,必须通过指针或引用传递和存储对象,常见的两种实现方式:
方式1:使用原始指针(需手动管理内存)
修改函数参数为指针,同时让devices数组存储Device*类型:
// 假设XYZ类的成员变量定义: static constexpr int MAX_DEVICES = 10; Device* devices[MAX_DEVICES]; void XYZ::setDevice(int num, Device* device) { printf("%s\n", typeid(*device).name()); // 现在会打印InputDevice this->devices[num] = device; } XYZ::XYZ() { printf("%s\n", typeid(InputDevice(cin)).name()); // 传入堆分配的派生类对象(注意后续要在析构函数中delete) setDevice(STANDARD_INPUT_DEVICE, new InputDevice(cin)); printf("%s\n", typeid(*devices[0]).name()); // 打印InputDevice } // 记得在XYZ的析构函数中释放内存: XYZ::~XYZ() { for (int i = 0; i < MAX_DEVICES; ++i) { delete devices[i]; } }
方式2:使用智能指针(自动管理内存,更安全)
用std::unique_ptr或std::shared_ptr替代原始指针,避免手动管理内存的麻烦:
#include <memory> // XYZ类的成员变量修改为智能指针数组: static constexpr int MAX_DEVICES = 10; std::unique_ptr<Device> devices[MAX_DEVICES]; void XYZ::setDevice(int num, std::unique_ptr<Device> device) { printf("%s\n", typeid(*device).name()); // 打印InputDevice this->devices[num] = std::move(device); } XYZ::XYZ() { printf("%s\n", typeid(InputDevice(cin)).name()); // 用make_unique创建派生类对象并传递 setDevice(STANDARD_INPUT_DEVICE, std::make_unique<InputDevice>(cin)); printf("%s\n", typeid(*devices[0]).name()); // 打印InputDevice }
额外注意事项
必须确保基类Device包含虚析构函数,否则销毁派生类对象时会出现未定义行为:
class Device { public: virtual ~Device() = default; // 虚析构函数,保证派生类对象正确析构 // 其他需要重写的虚函数 virtual void operate() { /* 基类实现 */ } }; class InputDevice : public Device { public: void operate() override { /* 派生类重写实现 */ } // 派生类专属函数 void readInput() { /* ... */ } };
内容的提问来源于stack exchange,提问作者GabrijelOkorn
相关产品推荐
相关产品推荐

