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

C++不使用模板如何实现不同类型的类成员字段重写?

问题根源

  1. 对象切片:Token类中存储的是TokenValue值类型而非指针/引用,传入子类对象构造Token时只会拷贝基类部分的内容,子类新增的成员会被直接截断,因此你访问到的永远是基类的void* value,初始为NULL所以打印出来是00000000。
  2. 成员隐藏:子类中定义的同名value是独立于基类的全新成员,基类的==运算符默认访问的是基类自身的void* value,不会读取子类的成员值。

修复方案

1. 改造继承体系避免对象切片与成员隐藏

首先修改TokenValue.h,删除基类无用的void* value,新增虚析构函数避免内存泄漏,将比较逻辑改为纯虚接口由子类各自实现:

// TokenValue.h
#include <string>
#include <typeinfo>

class TokenValue
{
public:
    virtual ~TokenValue() = default;
    virtual bool operator==(const TokenValue& tv) const = 0;
};

class TV_Empty : public TokenValue
{
public:
    bool operator==(const TokenValue& tv) const override
    {
        return typeid(*this) == typeid(tv);
    }
};

class TV_String : public TokenValue
{
public:
    std::string value;
    explicit TV_String(std::string v) : value(std::move(v)) {}

    bool operator==(const TokenValue& tv) const override
    {
        if (typeid(*this) != typeid(tv)) return false;
        const auto& other = dynamic_cast<const TV_String&>(tv);
        return value == other.value;
    }
};

class TV_Int : public TokenValue
{
public:
    int value;
    explicit TV_Int(int v) : value(v) {}

    bool operator==(const TokenValue& tv) const override
    {
        if (typeid(*this) != typeid(tv)) return false;
        const auto& other = dynamic_cast<const TV_Int&>(tv);
        return value == other.value;
    }
};

class TV_Float : public TokenValue
{
public:
    float value;
    explicit TV_Float(float v) : value(v) {}

    bool operator==(const TokenValue& tv) const override
    {
        if (typeid(*this) != typeid(tv)) return false;
        const auto& other = dynamic_cast<const TV_Float&>(tv);
        return value == other.value;
    }
};

然后修改Token.h,将值存储改为智能指针避免对象切片:

// Token.h
#include <memory>
#include "TokenValue.h"

class Token
{
public:
    enum class TokenType
    {
        // 所有支持的Token类型
    };

    TokenType type;
    std::unique_ptr<TokenValue> value;

    Token(TokenType type, std::unique_ptr<TokenValue> value) 
        : type(type), value(std::move(value)) {}
};

使用示例:

// 构造Token
auto str_val = std::make_unique<TV_String>("测试文本");
Token str_token(TokenType::STRING, std::move(str_val));

// 比较两个值
auto int_val1 = std::make_unique<TV_Int>(123);
auto int_val2 = std::make_unique<TV_Int>(123);
bool is_equal = (*int_val1) == (*int_val2); // 结果为true

2. 更简洁的替代方案(C++17及以上)

如果你的编译环境支持C++17,可以直接用std::variant替代继承体系,没有虚函数开销也不会出现切片问题:

#include <variant>
#include <string>

struct TV_Empty {};
// 直接用variant存储所有可能的Token值类型
using TokenValue = std::variant<TV_Empty, std::string, int, float>;

class Token
{
public:
    enum class TokenType { /* 自定义Token类型 */ };
    TokenType type;
    TokenValue value;
};
// variant原生支持==运算符,不需要自己实现比较逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 13:06:05