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

如何用单一函数指针存储不同签名函数实现StringList的Undo操作?

解决StringList类Undo操作中函数签名不匹配的问题

针对你遇到的函数指针签名不统一的问题,这里有几个实用的解决方案,不用定义多个函数指针就能搞定:

方案1:用函数对象(仿函数)封装反向操作

定义一个统一的基类作为undo命令的接口,然后为每个操作的反向逻辑创建子类,把需要的参数存在子类对象里,栈里只存基类指针,undo时统一调用无参的execute()方法即可。

示例代码:

#include <stack>
#include <memory>
#include <vector>
#include <string>

class StringList;

// 统一的undo命令基类
class UndoCommand {
public:
    virtual ~UndoCommand() = default;
    virtual void execute() = 0;
};

// InsertBefore的反向操作:移除插入的元素
class UndoInsertBefore : public UndoCommand {
private:
    StringList& list;
    int pos;
public:
    UndoInsertBefore(StringList& sl, int p) : list(sl), pos(p) {}
    void execute() override;
};

// RemoveBefore的反向操作:恢复被移除的元素
class UndoRemoveBefore : public UndoCommand {
private:
    StringList& list;
    int pos;
    std::string removedStr;
public:
    UndoRemoveBefore(StringList& sl, int p, const std::string& str) 
        : list(sl), pos(p), removedStr(str) {}
    void execute() override;
};

class StringList {
private:
    std::vector<std::string> data;
    std::stack<std::unique_ptr<UndoCommand>> undoStack;
public:
    void insert_before(int pos, const std::string& str) {
        data.insert(data.begin() + pos, str);
        undoStack.push(std::make_unique<UndoInsertBefore>(*this, pos));
    }

    void remove_before(int pos) {
        std::string removed = data[pos];
        data.erase(data.begin() + pos);
        undoStack.push(std::make_unique<UndoRemoveBefore>(*this, pos, removed));
    }

    void undo() {
        if (!undoStack.empty()) {
            undoStack.top()->execute();
            undoStack.pop();
        }
    }

    // 给子类提供访问内部数据的接口
    std::vector<std::string>& get_data() { return data; }
};

// 实现子类的execute方法
void UndoInsertBefore::execute() {
    list.get_data().erase(list.get_data().begin() + pos);
}

void UndoRemoveBefore::execute() {
    list.get_data().insert(list.get_data().begin() + pos, removedStr);
}

这种方式用面向对象的思路把参数和操作绑定,完美统一接口,不用关心每个操作的参数差异。

方案2:用Lambda表达式+std::function(最简洁)

C++11及以后可以用std::function<void()>存储任意可调用对象,包括捕获了参数的lambda。直接把反向操作和需要的参数通过lambda捕获,打包成无参的可调用对象压栈就行,代码量少很多。

示例代码:

#include <stack>
#include <functional>
#include <vector>
#include <string>

class StringList {
private:
    std::vector<std::string> data;
    std::stack<std::function<void()>> undoStack;
public:
    void insert_before(int pos, const std::string& str) {
        data.insert(data.begin() + pos, str);
        // 捕获当前对象和插入位置,打包成无参的undo操作
        undoStack.push([this, pos]() {
            data.erase(data.begin() + pos);
        });
    }

    void remove_before(int pos) {
        std::string removed = data[pos];
        int original_pos = pos;
        data.erase(data.begin() + pos);
        // 捕获需要恢复的参数,打包成无参操作
        undoStack.push([this, original_pos, removed]() {
            data.insert(data.begin() + original_pos, removed);
        });
    }

    void undo() {
        if (!undoStack.empty()) {
            undoStack.top()();
            undoStack.pop();
        }
    }
};

这个方案不用写额外的类,直接用lambda把参数和操作绑定,非常直观简洁。

方案3:用void*存储参数+统一处理函数(不推荐)

如果不能用C++11特性,也可以用结构体存函数指针和void*类型的参数,处理时强制转换类型。但这种方式类型不安全,还要手动管理内存,容易出bug,仅作为备选:

#include <stack>
#include <vector>
#include <string>

class StringList;

typedef void (*UndoFunc)(StringList*, void*);
struct UndoNode {
    UndoFunc func;
    void* args;
};

void undo_insert(StringList* list, void* args);
void undo_remove(StringList* list, void* args);

class StringList {
private:
    std::vector<std::string> data;
    std::stack<UndoNode> undoStack;
public:
    void insert_before(int pos, const std::string& str) {
        data.insert(data.begin() + pos, str);
        int* arg = new int(pos);
        undoStack.push({undo_insert, arg});
    }

    void remove_before(int pos) {
        std::string removed = data[pos];
        struct RemoveArgs { int pos; std::string str; };
        RemoveArgs* ra = new RemoveArgs{pos, removed};
        data.erase(data.begin() + pos);
        undoStack.push({undo_remove, ra});
    }

    void undo() {
        if (!undoStack.empty()) {
            UndoNode node = undoStack.top();
            node.func(this, node.args);
            undoStack.pop();
        }
    }

    std::vector<std::string>& get_data() { return data; }
};

void undo_insert(StringList* list, void* args) {
    int* pos = static_cast<int*>(args);
    list->get_data().erase(list->get_data().begin() + *pos);
    delete pos;
}

void undo_remove(StringList* list, void* args) {
    struct RemoveArgs { int pos; std::string str; };
    RemoveArgs* ra = static_cast<RemoveArgs*>(args);
    list->get_data().insert(list->get_data().begin() + ra->pos, ra->str);
    delete ra;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:43:11