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

C++中如何将多个相似Setter函数合并为通用函数?

解决方案:用通用模板函数封装重复逻辑

完全可以通过编写通用模板函数来封装foo(b)、调用B成员函数、bar(b)这三段重复逻辑,只需要将B的成员函数和对应参数作为参数传入即可,大幅减少代码冗余。

先看原来的冗余代码示例

假设你的类结构大致如下:

#include <string>

class B {
public:
    void doSomethingWithID(int id) { /* 具体业务逻辑 */ }
    void doSomethingWithName(const std::string& name) { /* 具体业务逻辑 */ }
    void doSomethingWithNumber(double num) { /* 具体业务逻辑 */ }
};

class A {
private:
    B b;
    void foo(B& obj) { /* 复杂的前置处理逻辑 */ }
    void bar(B& obj) { /* 复杂的后置处理逻辑 */ }
public:
    void setID(int id) {
        foo(b);
        b.doSomethingWithID(id);
        bar(b);
    }

    void setName(const std::string& name) {
        foo(b);
        b.doSomethingWithName(name);
        bar(b);
    }

    void setNumber(double num) {
        foo(b);
        b.doSomethingWithNumber(num);
        bar(b);
    }
    // 更多重复的setter函数...
};

优化后的通用实现

通过模板函数封装公共逻辑,只需要在每个setter中调用这个通用函数即可:

#include <string>
#include <functional> // 用于std::invoke(C++17+)

class B {
public:
    void doSomethingWithID(int id) { /* 具体业务逻辑 */ }
    void doSomethingWithName(const std::string& name) { /* 具体业务逻辑 */ }
    void doSomethingWithNumber(double num) { /* 具体业务逻辑 */ }
};

class A {
private:
    B b;
    void foo(B& obj) { /* 复杂的前置处理逻辑 */ }
    void bar(B& obj) { /* 复杂的后置处理逻辑 */ }

    // 通用set模板:兼容任意B的成员函数和参数列表
    template<typename Func, typename... Args>
    void genericSet(Func&& func, Args&&... args) {
        foo(b);
        // std::invoke支持成员函数指针、lambda等多种可调用对象
        std::invoke(std::forward<Func>(func), b, std::forward<Args>(args)...);
        bar(b);
    }
public:
    void setID(int id) {
        genericSet(&B::doSomethingWithID, id);
    }

    void setName(const std::string& name) {
        genericSet(&B::doSomethingWithName, name);
    }

    void setNumber(double num) {
        genericSet(&B::doSomethingWithNumber, num);
    }

    // 新增setter只需一行代码,比如新增setAge:
    // void setAge(int age) { genericSet(&B::doSomethingWithAge, age); }
};

关键细节说明

  1. 模板参数与完美转发:使用typename... Args可变参数模板和std::forward,确保参数能以正确的类型传递给B的成员函数,避免不必要的拷贝。
  2. std::invoke的作用:C17引入的std::invoke可以统一处理成员函数指针、普通函数、lambda等可调用对象,让通用函数更灵活。如果你的项目基于C11/14,可以直接用成员函数指针调用语法替代:
    (b.*func)(std::forward<Args>(args)...);
    
  3. 维护性提升:后续修改foo或bar的逻辑时,只需要修改genericSet中的一处代码;新增setter时,只需要调用genericSet并传入对应的B成员函数和参数即可,完全避免重复编写前置/后置逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 19:17:37