You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复C++混合Vehicle子类数组中的对象切割问题?

解决C++对象切割与多态打印问题

你的判断完全正确:问题核心就是对象切割。当前Road类中vehicles是Vehicle类型的数组,存储的是实际的基类对象,而非指向子类对象的指针/引用。当你将Car或Lorry对象赋值给数组中的Vehicle元素时,子类特有的成员(比如Car的currentLane)会被切割丢弃,同时虚函数表也会被替换为基类的,导致无法触发子类的print方法。

下面是具体的解决方案:

1. 给基类添加虚析构与克隆方法

多态场景下必须给基类添加虚析构函数,否则销毁子类指针时无法调用子类析构;同时需要添加克隆方法,用于创建子类对象的副本,避免直接赋值导致切割。

修改Vehicle类:

class Vehicle
{
    int speed;
    int entryTime;
    int currentPositionInLane;
    int minimumFollowingDistance;
public:
    // 虚析构函数,确保子类析构被正确调用
    virtual ~Vehicle() = default;

    virtual void print() const {
        std::cout << "speed: " << speed << std::endl;
        std::cout << "entryTime: " << entryTime << std::endl;
        std::cout << "currentPositionInLane: " << currentPositionInLane << std::endl;
        std::cout << "minimumFollowingDistance: " << minimumFollowingDistance << std::endl;
    }

    // 纯虚克隆方法,子类必须实现
    virtual Vehicle* clone() const = 0;
};

2. 子类实现克隆方法

让Car和Lorry分别实现clone方法,返回自身对象的副本:

Car类修改

class Car : public Vehicle
{
    int currentLane;
public:
    Car(int, int, int, int, int);
    void pass(const Vehicle&);
    void print() const override {
        Vehicle::print();
        std::cout << "currentLane: " << currentLane << std::endl;
    }

    // 实现克隆方法
    Vehicle* clone() const override {
        return new Car(*this);
    }
};

Lorry类修改

class Lorry: public Vehicle
{
public:
    Lorry(int speed, int entryTime, int currentPositionInLane, int minimumFollowingDistance)
        : Vehicle(speed, entryTime, currentPositionInLane, minimumFollowingDistance){}

    // 实现克隆方法
    Vehicle* clone() const override {
        return new Lorry(*this);
    }
};

3. 修改Road类的成员与方法

将Road中存储车辆的数组改为指针数组(或用智能指针更安全),存储指向子类对象的指针,保留多态性。

修改Road类定义

class Road
{
    double updateFrequency;
    double currentTime;
    Vehicle** vehicles; // 改为指针数组,存储指向Vehicle子类的指针
    int vehicleCount;
public:
    Road();
    ~Road(); // 添加析构函数释放内存
    void update();
    bool checkIfFinished();
    void checkForUserInterrupt();
    void saveToFile();
    bool setCurrentTime(double);
    bool setUpdateFrequency(double);
    void addVehicle(const Vehicle& vehicle);

    void print();
};

实现Road的构造、析构与addVehicle方法

// 构造函数初始化成员
Road::Road() : updateFrequency(0), currentTime(0), vehicles(nullptr), vehicleCount(0) {}

// 析构函数释放所有车辆对象与指针数组
Road::~Road() {
    for (int i = 0; i < vehicleCount; i++) {
        delete vehicles[i]; // 调用子类析构
    }
    delete[] vehicles; // 释放指针数组
}

// 修改addVehicle,通过克隆创建子类副本并存储指针
void Road::addVehicle(const Vehicle& vehicle) {
    Vehicle** temp = new Vehicle*[vehicleCount + 1];
    // 复制原有指针
    for (int i = 0; i < vehicleCount; i++) {
        temp[i] = vehicles[i];
    }
    // 克隆传入的车辆对象,存储子类指针
    temp[vehicleCount] = vehicle.clone();
    vehicleCount++;

    // 替换旧数组
    delete[] vehicles;
    vehicles = temp;
}

修改Road的print方法

通过指针调用虚函数,触发动态绑定:

void Road::print() {
    std::cout << "updateFrequency: " << updateFrequency << std::endl;
    std::cout << "currentTime: " << currentTime << std::endl;
    std::cout << std::endl << "The vehicles on the road: " << std::endl << std::endl;
    for (int i = 0; i < vehicleCount; i++)
    {
        vehicles[i]->print(); // 指针调用虚函数,自动匹配子类实现
        std::cout << std::endl;
    }
}

更安全的替代方案:使用智能指针

如果不想手动管理内存,可以用std::vector<std::unique_ptr<Vehicle>>替代原始指针数组,避免内存泄漏:

修改Road类成员:

#include <vector>
#include <memory>

class Road
{
    double updateFrequency;
    double currentTime;
    std::vector<std::unique_ptr<Vehicle>> vehicles; // 用智能指针容器
public:
    // ... 其他方法不变
    void addVehicle(const Vehicle& vehicle) {
        // 克隆对象并放入智能指针容器
        vehicles.push_back(std::unique_ptr<Vehicle>(vehicle.clone()));
    }

    void print() {
        std::cout << "updateFrequency: " << updateFrequency << std::endl;
        std::cout << "currentTime: " << currentTime << std::endl;
        std::cout << "\nThe vehicles on the road: \n\n";
        for (const auto& veh : vehicles) {
            veh->print();
            std::cout << "\n";
        }
    }
};

这种方式不需要手动写析构函数,智能指针会自动管理对象生命周期。

内容的提问来源于stack exchange,提问作者jdsflk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 00:07:06