首页 > 解决方案 > C++ 是否有定义的方法来传递指向类成员对象的成员函数的指针?

问题描述

假设我有一些功能:

void myFunction(void (MyClass::*function)(int), MyClass& myClass) {
    (myClass.*function)(1);
}

这被称为如下:

class MyClass {
    int value;

    void setValue(int value) {
        this->value = value;
    }
}

MyClass myClass;
myFunction(&MyClass::set_value, myClass);

这个函数接受对象myClass并调用它的成员函数setValue,它调用它的参数设置为 1。

在我意识到 C++ 支持将成员函数作为参数传递之前,我已经手动设置我的代码以接收对象和函数指针,然后确定它们地址之间的偏移量。如果给定相同类型对象的不同实例,则可以保存此偏移量以调用相同的成员函数。

但是,是的,然后我发现你可以做到Class::*function(我假设)完全按照我之前构建/描述的方式。

这导致了我的问题,假设我具有与以前相同的功能,除了我稍微改变了我的类结构:

class MyClass {
    ChildClass childClass;
}

class ChildClass {
    int value;

    void setValue(int value) {
        this->value = value;
    }
}

那么在 C++ 中有没有办法将setValue函数传递myFunctionsetValue现在在ChildClass对象内的给定函数MyClass

最明显的解决方案是添加一个setValue成员函数,在其对象MyClass中调用该函数,如下所示:setValuechildClass

class MyClass {
    ChildClass childClass;

    void setValue(int value) {
        this->childClass.setValue(value);
    }
}

class ChildClass {
    int value;

    void setValue(int value) {
        this->value = value;
    }
}

MyClass myClass;
myFunction(&MyClass::setValue, myClass);

但是,由于我正在研究的项目的语义,这不是一个理想的解决方案。因此,我很好奇是否有办法在 C++ 中实现这一点。如果没有,我当然可以手动实现它(它和以前一样,除了你要保存成员之间的偏移量childClassMyClass以及成员和的偏移量setValueChildClass,但我自然想知道是否有是一种更“内置”的方式来实现这一点。

标签: c++

解决方案


鉴于 setValue 现在位于 MyClass 的 ChildClass 对象中,C++ 中是否有办法将 setValue 函数传递给 myFunction?

有一种方法是添加一个间接级别。该间接级别是多态函数包装器std::functionmyFunction可以接受一个std::function参数,该参数可以使用任意访问器函数进行初始化,包括 labdas。例如:

#include <functional>

struct ChildClass {
    int value;

    void setValue(int value) {
        this->value = value;
    }
};

struct MyClass {
    ChildClass childClass;
};

void myFunction(std::function<void(MyClass&, int)> const& f, MyClass& myClass) {
    f(myClass, 1);
}

int main() {
    MyClass myClass;
    myFunction([](MyClass& a, int b) { a.childClass.setValue(b); }, myClass);
}

使用std::function您可以摆脱MyClass&参数并期望用户提供std::function由 lambda 表达式捕获的所需对象:

void myFunction2(std::function<void(int)> const& f) {
    f(1);
}

int main() {
    MyClass myClass;
    myFunction2([&myClass](int b) { myClass.childClass.setValue(b); });
}

注意std::function至少可以sizeof(void(Undefined_class::*member_pointer)())在对象内部存储而不分配堆内存。C++ 标准没有要求,但是,这种优化的原因似乎是使用std::function成员函数指针并不比直接使用成员函数指针差多少。或者,换句话说,如果您将代码中的成员和成员函数指针替换为std::function,您的应用程序将不会因该†</sup>的额外内存分配而受到惩罚。在gccx86_64 上会产生 16 个字节的 inline 存储 in std::function,它可以存储一个带有 2 个对象引用的 lambda 捕获对象。

†</sup> 的大小std::function仍然比这大,而且它是一个非平凡的类型,所以它不能在寄存器中传递或返回


推荐阅读