1. C++多态与容器存储的核心问题
在C++面向对象编程中,多态性是一个强大的特性,它允许我们通过基类指针或引用来操作派生类对象。但当我们需要在容器(如vector)中存储多态对象时,存储方式的选择会直接影响程序的行为和性能。让我们从一个实际案例出发:
假设我们有一个基类ODU和它的派生类ODU331、ODU335(其中ODU335又是ODU331的子类)。ODU类中定义了一些虚函数,这些函数在派生类中被重写。现在我们需要在vector容器中存储这些对象,并保持多态行为。
关键理解:C++中对象切片(Object Slicing)问题是指当派生类对象被赋值给基类对象时,派生类特有的部分会被"切掉",只保留基类部分。这是多态与容器结合使用时最常见的陷阱。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三种存储方式的深度对比
2.1 方式一:直接存储对象(非指针方式)
cpp复制vector<ODU> devices;
devices.push_back(ODU331()); // 对象切片发生在这里
devices.push_back(ODU335()); // 再次发生对象切片
这种方式的问题在于:
- 当派生类对象被放入vector时,会发生对象切片
- 派生类特有的成员变量和方法都会丢失
- 虚函数表指针也被复制为基类的版本,多态性完全失效
实测表现:
- 通过devices[0]或devices[1]调用的任何虚函数都只会执行ODU基类的版本
- 无法通过dynamic_cast将元素转换回原始派生类类型
- sizeof(devices[0]) == sizeof(ODU),无论原始对象是什么类型
2.2 方式二:存储裸指针但不使用new
cpp复制vector<ODU*> devices;
ODU331 obj331;
ODU335 obj335;
devices.push_back(&obj331);
devices.push_back(&obj335);
这种方式的特点:
- 避免了对象切片,因为存储的是指针而非对象本身
- 保持了多态性,虚函数调用能正确分发到派生类实现
- 但存在严重生命周期管理问题:
- 当局部对象(obj331/obj335)离开作用域被销毁后
- vector
