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

C++中存储基类指针且可调用派生类函数的最优实现方案

C++ Cell类存储派生类指针优化方案

现有代码的问题

  • 拼写错误:std::dyanmic_pointer_cast应为std::dynamic_pointer_cast,类型判断中误用赋值符=代替比较符==
  • 手动维护CellContentType枚举和实际指针类型的映射,容易出现不一致的bug,比如dynamic_pointer_cast转型失败时,枚举值仍被错误设置
  • 运行时判断编译期即可确定的模板参数类型,存在冗余开销
  • 成员变量公开,不符合封装原则
  • main函数中需要手动判断类型再转型,代码冗余扩展性差,新增派生类时需要修改所有判断分支

最优实现方案

核心思路是利用C++面向对象的多态特性,通过虚函数表自动完成类型调度,完全避免手动类型判断。

方案1:基类定义统一虚接口(最常用,适合绝大多数场景)

在虚基类CellContent中定义所有派生类都需要实现的公共虚接口,调用时直接通过基类指针调用即可,不需要关心实际派生类型。

#include <memory>
#include <iostream>

// 虚基类
class CellContent {
public:
    virtual ~CellContent() = default; // 虚基类必须声明虚析构函数
    // 定义公共虚接口,示例为玩家踩中单元格的触发逻辑
    virtual void onTrigger() = 0;
};

class Enemy : public CellContent {
public:
    void onTrigger() override {
        std::cout << "遭遇敌人,进入战斗\n";
    }
    // Enemy专属方法
    void attack() {
        std::cout << "敌人发动攻击\n";
    }
};

class Item : public CellContent {
public:
    void onTrigger() override {
        std::cout << "拾取到道具\n";
    }
    // Item专属方法
    void use() {
        std::cout << "使用道具\n";
    }
};

class Cell {
private:
    std::shared_ptr<CellContent> _cellContent;
public:
    void setCellContent(std::shared_ptr<CellContent> content) {
        _cellContent = std::move(content);
    }

    CellContent* getCellContent() {
        return _cellContent.get();
    }

    // 保留安全转型方法,供需要调用派生类专属方法的场景使用
    template<typename T>
    std::shared_ptr<T> getCellContentAs() {
        return std::dynamic_pointer_cast<T>(_cellContent);
    }
};

int main() {
    auto enemy = std::make_shared<Enemy>();
    Cell cell;
    cell.setCellContent(enemy);

    // 直接调用虚接口,自动调度到对应派生类实现,无任何if分支
    cell.getCellContent()->onTrigger();
    return 0;
}

方案2:访问者模式(适合需要对不同派生类执行大量专属逻辑的场景)

如果需要频繁调用派生类的专属方法,又不想到处写转型判断,可以用访问者模式将操作封装,彻底消除所有类型判断分支:

#include <memory>
#include <iostream>

// 派生类前向声明
class Enemy;
class Item;

// 访问者基类
class CellContentVisitor {
public:
    virtual void visit(Enemy& enemy) = 0;
    virtual void visit(Item& item) = 0;
};

class CellContent {
public:
    virtual ~CellContent() = default;
    virtual void accept(CellContentVisitor& visitor) = 0;
};

class Enemy : public CellContent {
public:
    void accept(CellContentVisitor& visitor) override {
        visitor.visit(*this);
    }
    void attack() {
        std::cout << "敌人发动攻击\n";
    }
};

class Item : public CellContent {
public:
    void accept(CellContentVisitor& visitor) override {
        visitor.visit(*this);
    }
    void use() {
        std::cout << "使用道具\n";
    }
};

class Cell {
private:
    std::shared_ptr<CellContent> _cellContent;
public:
    void setCellContent(std::shared_ptr<CellContent> content) {
        _cellContent = std::move(content);
    }
    CellContent* getCellContent() {
        return _cellContent.get();
    }
};

// 实现具体的交互访问者
class InteractVisitor : public CellContentVisitor {
public:
    void visit(Enemy& enemy) override {
        enemy.attack();
    }
    void visit(Item& item) override {
        item.use();
    }
};

int main() {
    auto enemy = std::make_shared<Enemy>();
    Cell cell;
    cell.setCellContent(enemy);

    InteractVisitor visitor;
    // 自动调度到对应派生类的处理逻辑,无任何if分支
    cell.getCellContent()->accept(visitor);
    return 0;
}

优化优势

  • 不需要手动维护类型枚举,完全避免类型不匹配的bug
  • 新增派生类时只需要实现对应的虚接口/访问方法,不需要修改原有调用逻辑,符合开闭原则
  • 代码更简洁,无冗余的类型判断分支

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 20:45:03