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

如何为基类结构体赋值,向下转型为shared_ptr时不重置数据

编程语言Token派生类存储与类型转换优化方案

开发编程语言时,用结构体表示Token,需要实现基类Token向派生类(如BaseToken→VariableToken、BaseToken→FunctionToken)的转换,并将这些派生类存入基类型的集合中;遍历集合时,还要能转回对应派生类以获取专属数据。

当前代码实现与问题

现有结构体定义:

#include<iostream>
#include<memory>
#include<vector>

enum class Enums
{
    A,
    B,
    UNKNOWN,
};

struct BaseStruct
{
    Enums Type = Enums::UNKNOWN;
};

struct DerivedStruct : public BaseStruct
{
    int MoreData = 0;
};

struct AnotherDerivedStruct : public BaseStruct
{
    char different_Data;
};

测试代码中存在的核心问题:先创建基类实例并赋值Type,再替换为派生类实例时,原Type数据会被重置;存入std::vector<std::shared_ptr<BaseStruct>>后,无法直接获取派生类的专属字段。

int main()
{
    auto BaseToken = std::make_shared<BaseStruct>();
    BaseToken->Type = Enums::B;
    
    bool ComplicatedLogicalLogic = false;
    
    if (ComplicatedLogicalLogic)
    {
        // 创建派生类实例会重置Type,原赋值的Enums::B丢失
        BaseToken = std::make_shared<DerivedStruct>();
        auto DerivedToken = std::static_pointer_cast<DerivedStruct>(BaseToken);
        // DerivedToken->Type此时是默认的UNKNOWN
    }
    else
    {
        BaseToken = std::make_shared<AnotherDerivedStruct>();
        auto DerivedToken = std::static_pointer_cast<AnotherDerivedStruct>(BaseToken);
        
        // 因为Type被重置,这个条件永远不成立
        if (DerivedToken->Type == Enums::B)
        {
            std::cout << "IS B" << '\n';
        }
    }
}

优化方案

1. 先创建派生类实例,再赋值基类属性

不要先创建基类再替换为派生类,直接初始化派生类实例,再通过基类指针操作基类属性,这样派生类的专属数据和基类属性都能保留:

int main() {
    std::vector<std::shared_ptr<BaseStruct>> tokenList;
    bool ComplicatedLogicalLogic = false;

    if (ComplicatedLogicalLogic) {
        auto derivedToken = std::make_shared<DerivedStruct>();
        derivedToken->Type = Enums::A;
        derivedToken->MoreData = 100;
        tokenList.push_back(derivedToken);
    } else {
        auto anotherDerivedToken = std::make_shared<AnotherDerivedStruct>();
        anotherDerivedToken->Type = Enums::B;
        anotherDerivedToken->different_Data = 'X';
        tokenList.push_back(anotherDerivedToken);
    }
}

2. 使用dynamic_cast安全向下转型

遍历集合时,用dynamic_cast代替static_cast,它会在类型不匹配时返回空指针,避免未定义行为;结合Type枚举判断类型,确保转型安全:

// 遍历tokenList
for (const auto& token : tokenList) {
    switch (token->Type) {
        case Enums::A: {
            auto derived = std::dynamic_pointer_cast<DerivedStruct>(token);
            if (derived) {
                std::cout << "DerivedStruct: Type=A, MoreData=" << derived->MoreData << std::endl;
            }
            break;
        }
        case Enums::B: {
            auto anotherDerived = std::dynamic_pointer_cast<AnotherDerivedStruct>(token);
            if (anotherDerived) {
                std::cout << "AnotherDerivedStruct: Type=B, different_Data=" << anotherDerived->different_Data << std::endl;
            }
            break;
        }
        default:
            std::cout << "Unknown token type" << std::endl;
    }
}

3. 用多态(虚函数)简化操作

在基类中定义纯虚函数,让派生类实现各自的业务逻辑,遍历集合时无需手动转型,直接调用虚函数即可,更符合面向对象设计:

struct BaseStruct
{
    Enums Type = Enums::UNKNOWN;
    // 必须加虚析构,避免基类指针销毁派生类时内存泄漏
    virtual ~BaseStruct() = default;
    // 纯虚函数,派生类实现各自的处理逻辑
    virtual void process() const = 0;
};

struct DerivedStruct : public BaseStruct
{
    int MoreData = 0;
    void process() const override {
        std::cout << "Processing DerivedStruct: Type=" << static_cast<int>(Type) << ", MoreData=" << MoreData << std::endl;
    }
};

struct AnotherDerivedStruct : public BaseStruct
{
    char different_Data;
    void process() const override {
        std::cout << "Processing AnotherDerivedStruct: Type=" << static_cast<int>(Type) << ", different_Data=" << different_Data << std::endl;
    }
};

// 遍历处理
for (const auto& token : tokenList) {
    token->process();
}

完整示例代码

#include<iostream>
#include<memory>
#include<vector>

enum class Enums
{
    A,
    B,
    UNKNOWN,
};

struct BaseStruct
{
    Enums Type = Enums::UNKNOWN;
    virtual ~BaseStruct() = default;
    virtual void process() const = 0;
};

struct DerivedStruct : public BaseStruct
{
    int MoreData = 0;
    void process() const override {
        std::cout << "DerivedStruct - Type: " << static_cast<int>(Type) << ", MoreData: " << MoreData << "\n";
    }
};

struct AnotherDerivedStruct : public BaseStruct
{
    char different_Data;
    void process() const override {
        std::cout << "AnotherDerivedStruct - Type: " << static_cast<int>(Type) << ", different_Data: " << different_Data << "\n";
    }
};

int main() {
    std::vector<std::shared_ptr<BaseStruct>> tokenList;
    bool ComplicatedLogicalLogic = false;

    // 创建派生类并添加到集合
    if (ComplicatedLogicalLogic) {
        auto derived = std::make_shared<DerivedStruct>();
        derived->Type = Enums::A;
        derived->MoreData = 200;
        tokenList.push_back(derived);
    } else {
        auto anotherDerived = std::make_shared<AnotherDerivedStruct>();
        anotherDerived->Type = Enums::B;
        anotherDerived->different_Data = 'Y';
        tokenList.push_back(anotherDerived);
    }

    // 多态处理
    std::cout << "=== 多态方式处理 ===" << "\n";
    for (const auto& token : tokenList) {
        token->process();
    }

    // 转型方式处理
    std::cout << "\n=== 转型方式处理 ===" << "\n";
    for (const auto& token : tokenList) {
        if (token->Type == Enums::A) {
            auto derived = std::dynamic_pointer_cast<DerivedStruct>(token);
            if (derived) {
                std::cout << "DerivedStruct: MoreData=" << derived->MoreData << "\n";
            }
        } else if (token->Type == Enums::B) {
            auto anotherDerived = std::dynamic_pointer_cast<AnotherDerivedStruct>(token);
            if (anotherDerived) {
                std::cout << "AnotherDerivedStruct: different_Data=" << anotherDerived->different_Data << "\n";
            }
        }
    }

    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:40:22