如何为基类结构体赋值,向下转型为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
相关产品推荐
相关产品推荐

