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

如何遍历模板化MenuNode类的链表结构?

通用LCD菜单模板类改造方案

我正在为4行LCD开发通用菜单类,现有非模板版本仅支持int类型数据,希望扩展为模板类以支持int、float、unsigned等多种类型。但直接改为模板类后,不同类型的MenuNode实例属于不同类型,无法用统一指针遍历菜单结构,核心问题是如何实现跨类型的菜单遍历。


核心解决方案:分离导航逻辑与数据类型

通过非模板基类+模板子类的结构解决问题:

  1. 定义非模板基类,封装所有菜单导航相关的成员(父/子/兄弟节点指针、提示文本、导航方法),与数据类型完全无关;
  2. 模板子类继承基类,专门处理特定类型的数据存储与读写;
  3. 利用虚函数实现不同类型值的统一输出,确保遍历逻辑无需关心具体数据类型。

1. 定义非模板基类 MenuNodeBase

这个基类负责所有导航逻辑,是所有菜单节点的统一接口:

/*
 * 菜单节点基类:处理导航逻辑,与数据类型无关
 */
class MenuNodeBase
{
private:
    char* prompt;
public:
    MenuNodeBase* parent = NULL;
    MenuNodeBase* child = NULL;
    MenuNodeBase* prevSibling = NULL;
    MenuNodeBase* nextSibling = NULL;

    char* Prompt()
    {
        return prompt;
    }

    MenuNodeBase(char* prompt, MenuNodeBase* parent, MenuNodeBase* prevSibling)
    {
        Serial.print(prompt);
        Serial.println(F(" MenuNodeBase"));
        this->prompt = prompt;
        if (prevSibling != NULL)
        {
            this->prevSibling = prevSibling;
            prevSibling->SetNextSibling(this);
            this->parent = prevSibling->parent;
        }
        if (prevSibling == NULL && parent != NULL)
        {
            this->parent = parent;
            this->parent->SetChild(this);
        }
    }

    void SetChild(MenuNodeBase* child)
    {
        Serial.print(prompt);
        Serial.println(F(" SetChild"));
        this->child = child;
    }

    void SetNextSibling(MenuNodeBase* nextSibling)
    {
        Serial.print(prompt);
        Serial.println(F(" SetNextSibling"));
        this->nextSibling = nextSibling;
    }

    // 纯虚函数,强制子类实现值的打印逻辑
    virtual void PrintValue() = 0;
};

2. 定义模板子类 MenuNode<T>

继承基类,添加类型安全的数据读写方法:

/*
 * 模板菜单节点类:处理特定类型的数据
 */
template<typename T>
class MenuNode : public MenuNodeBase
{
private:
    T value;
public:
    MenuNode(char* prompt, T initialValue, MenuNodeBase* parent, MenuNodeBase* prevSibling)
        : MenuNodeBase(prompt, parent, prevSibling)
    {
        value = initialValue;
    }

    void SetValue(T value)
    {
        this->value = value;
    }

    T GetValue()
    {
        return value;
    }

    // 实现基类的虚函数,适配当前类型的打印
    void PrintValue() override
    {
        Serial.print(value);
    }
};

3. 修改遍历打印函数

使用基类指针MenuNodeBase*遍历,通过虚函数PrintValue()自动适配不同类型的值:

void PrintMenuStructure(MenuNodeBase* node, int offset)
{
    while (node != NULL)
    {
        for (int i = 0; i < offset; i++)
            Serial.print("-");
        Serial.print(node->Prompt());
        Serial.print(" = ");
        node->PrintValue(); // 调用虚函数,自动匹配数据类型

        if (node->parent != NULL)
        {
            Serial.print(" parent=");
            Serial.print(node->parent->Prompt());
        }
        if (node->prevSibling != NULL)
        {
            Serial.print(" prevSib=");
            Serial.print(node->prevSibling->Prompt());
        }
        if (node->nextSibling != NULL)
        {
            Serial.print(" nextSib=");
            Serial.print(node->nextSibling->Prompt());
        }
        if (node->child != NULL)
        {
            Serial.print(" child=");
            Serial.print(node->child->Prompt());
        }
        Serial.println();

        if (node->child != NULL)
            PrintMenuStructure(node->child, offset + 1);
        node = node->nextSibling;
    }
}

4. 混合类型测试代码

现在可以创建不同数据类型的菜单节点,且能正常遍历:

// 测试菜单:混合int、float、unsigned类型
MenuNode<int> r1("R1", 10, NULL, NULL);
MenuNode<float> r2("R2", 20.5f, NULL, &r1);
    MenuNode<unsigned> r21("R21", 30u, &r2, NULL);
    MenuNode<int> r22("R22", 40, &r2, &r21);
        MenuNode<float> r221("R221", 50.2f, &r22, NULL);
            MenuNode<unsigned> r2211("R2211", 60u, &r221, NULL);
            MenuNode<int> r2212("R2212", 70, NULL, &r2211);
MenuNode<float> r3("R3", 30.8f, NULL, &r2);

// 启动遍历打印
PrintMenuStructure(&r1, 0);

关键说明

  • 基类MenuNodeBase确保所有节点可以通过统一指针访问导航逻辑,解决了模板类实例类型不兼容的问题;
  • 模板子类MenuNode<T>提供类型安全的数据操作,虚函数PrintValue()实现了遍历过程中的统一输出;
  • 如果需要对特定类型节点做针对性操作,可以使用dynamic_cast<MenuNode<T>*>(node)进行类型转换(需确保类型匹配)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 22:25:29