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

问询:能否不使用this->*调用类成员函数指针?

成员函数指针调用的替代语法问题

我编写了一个用于查找关键字并执行关联成员函数的类,代码如下:

#include <iostream>
#include <string>
#include <map>
class Example;

typedef std::map<
    std::string, void (Example::*)(const std::string &)> ExampleList;
typedef ExampleList::iterator ExampleIter;

class Example
{
public:
    ExampleList lut;
    Example()
    {
        lut["aaa"] = &Example::aaa;
        lut["bbb"] = &Example::bbb;
    }

    void lookup(const std::string& line)
    {
        // 获取关键字
        std::size_t keylen = line.find(' ', 0);
        std::string keyword = line;
        if (keylen != line.npos)
            keyword = line.substr(0, keylen);

        // 检查是否为已知关键字
        ExampleIter eit = lut.find(keyword);
        if (eit == lut.end())
        {
            std::cout << "无法处理关键字: " << keyword << std::endl;
            return;
        }

        // 找到匹配项,执行处理函数
        (this->*(eit->second))(line);  // << 是否存在不需要this->*的替代语法?
    }

    void aaa(const std::string& info)
    {
        std::cout << "执行aaa处理函数" << std::endl;
    }
    void bbb(const std::string& info)
    {
        std::cout << "执行bbb处理函数" << std::endl;
    }
};

int main()
{
    Example eg;
    eg.lookup("aaa");    // 正常执行
    eg.lookup("bbb is legal"); // 正常执行
    eg.lookup("bbbb is illegal"); // 失败:bbbb未定义
    eg.lookup("cc"); // 失败:cc未定义
    eg.lookup("aaaa"); // 失败:aaaa未定义 
}

在lookup函数末尾,我通过(this->*(eit->second))(line);执行处理函数,想了解是否存在不使用this->*的替代调用语法。


可行的替代方案

1. 使用C++17的std::invoke

std::invoke是C++17引入的通用调用工具,可以统一处理普通函数、成员函数指针、函数对象等的调用逻辑,无需手动编写this->*语法。需要先包含<functional>头文件,调用方式如下:

std::invoke(eit->second, this, line);

它会自动完成成员函数指针与当前对象的绑定,代码更简洁易读。

2. 改用std::function存储绑定后的函数

如果允许修改lut的类型,可以将成员函数指针替换为绑定了当前对象的std::function,这样调用时完全不需要this->*:

#include <functional> // 需包含此头文件

class Example
{
public:
    // 修改map的存储类型为std::function
    std::map<std::string, std::function<void(const std::string&)>> lut;
    Example()
    {
        // 用lambda捕获当前对象,绑定成员函数
        lut["aaa"] = [this](const std::string& info) { this->aaa(info); };
        lut["bbb"] = [this](const std::string& info) { this->bbb(info); };
    }

    void lookup(const std::string& line)
    {
        // ... 关键字查找逻辑保持不变 ...

        // 直接调用函数对象即可
        eit->second(line);
    }

    // ... 成员函数aaa、bbb保持不变 ...
};

这种方式的调用语法和普通函数完全一致,可读性更高,仅会带来可忽略的lambda额外开销。

3. 封装调用逻辑(避免重复写this->*)

可以写一个简单的辅助成员函数,封装成员函数指针的调用逻辑,减少重复代码:

class Example
{
    // ... 其他成员 ...
private:
    void callHandler(void (Example::*handler)(const std::string&), const std::string& arg)
    {
        (this->*handler)(arg);
    }
};

然后在lookup中调用:

callHandler(eit->second, line);

这种方式本质还是依赖this->*,但可以避免在业务代码中重复书写该语法。


为什么必须绑定对象?

非静态成员函数的指针本身不包含对象实例信息,必须和具体对象(这里是this指向的当前实例)绑定才能确定调用上下文,因此绕开对象实例直接调用成员函数指针是不可能的。上述方案都是通过不同方式隐式处理了绑定逻辑,而非真正消除对象依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 17:13:19