类成员函数作为函数指针

Class member function as function pointer

本文关键字:函数 指针 成员      更新时间:2023-10-16

我有一个类,它的一个成员函数实际上是一个函数指针。这样用户就可以重写这个函数的功能。不幸的是,我在运行这个函数时遇到了一些困难。我用g++来编译。

代码如下:

    #include <iostream>
    using namespace std;
    double fcn_mod(const double &phit){
        return 1.2+phit;
    }
    class Object{
        public:
            Object() {
                fcn_ptr = (double (*)(const double &)) &Object::fcn_default;
            }
            double (*fcn_ptr)(const double &) = NULL;
        private:
            double fcn_default(const double &phit){
                return 3.2+phit;
            }
    };

    int main(){
        Object test1,test2;
        cout << (test1.*fcn_ptr)(2) << endl; // can not compile here
        test2.fcn_ptr = &fcn_mod;
        cout << (test2.*fcn_ptr)(2) << endl; // and here
        cout << "test" << endl;
    }

错误信息是:

    erreur: ‘fcn_ptr’ was not declared in this scope

+++++ UPDATE 1 +++++

考虑到注释,这里是一个更简洁的版本:

    #include <iostream>
    using namespace std;
    double fcn_mod(const double &phit){
        return 1.2+phit;
    }
    double fcn_default(const double &phit){
        return 3.2+phit;
    }
    class Object{
        public:
            double (*fcn_ptr)(const double &) = NULL;
            Object() {
                fcn_ptr = &fcn_default;
            }
    };

    int main(){
        Object test1,test2;
        cout << (test1.*fcn_ptr)(2) << endl; // can not compile here
        test2.fcn_ptr = &fcn_mod;
        //cout << (test2.*fcn_ptr)(2) << endl; // and here
        cout << "test" << endl;
    }

这也是一个更好的方法:

    #include <iostream>
    using namespace std;
    double fcn_mod(const double &phit){
        return 1.2+phit;
    }
    class Object{
        public:
            Object() {
                fcn_ptr = &fcn_default;
            }
            double (*fcn_ptr)(const double &) = NULL;
        private :
            static double fcn_default(const double &phit){
                return 3.2+phit;
            }
    };
    int main(){
        Object test1,test2;
        cout << (test1.*fcn_ptr)(2) << endl; // can not compile here
        test2.fcn_ptr = &fcn_mod;
        cout << (test2.*fcn_ptr)(2) << endl; // and here
        cout << "test" << endl;
    }

+++++ UPDATE 2 +++++

如果我想通过这个函数访问类的成员该怎么办?

最简单的解决方案是不能从fcn_mod中访问类成员(aa)。

#include <iostream>
using namespace std;
double fcn_mod(const double &phit){
    return 1.2 + phit + aa*0.001; // can not compile here
}
class Object{
    public:
        Object() {
            fcn_ptr = &Object::fcn_default;
            aa = 4;
        }
        double (*fcn_ptr)(const double &) = NULL;
        double aa;
    private:
        static double fcn_default(const double &phit){
            return 3.2 + phit + aa*0.001; // and here
        }
};
int main(){
    Object test1,test2;
    cout << (test1.fcn_ptr)(2) << endl;
    test2.fcn_ptr = &fcn_mod;
    cout << (test2.fcn_ptr)(2) << endl;
    cout << "test" << endl;
}

但是使用std::bind和std::function的解决方案也不需要。我可以传递一种"静态"参数的函数指针?

我添加了一个网关功能。

#include <iostream>
using namespace std;
double fcn_mod(const double &phit){
    return 1.2 + phit;
}
class Object{
    public:
        Object() {
            fcn_ptr = &Object::fcn_default;
            aa = 4;
        }
        double do_something(const double &phit){
            return this->fcn_ptr(phit+aa*0.001);
        }
        double (*fcn_ptr)(const double &);
        double aa;
    private:
        static double fcn_default(const double &phit){
            return 3.2 + phit;
        }
};
int main(){
    Object test1,test2;
    cout << test1.do_something(2) << endl; // can not compile here
    test2.fcn_ptr = &fcn_mod;
    cout << test2.do_something(2) << endl; // and here
    cout << "test" << endl;
}

你想做的是不会成功的。指向非静态成员函数的指针与指向自由函数的指针不同,因为与后者不同,前者必须在对象的实例上调用。因此,不能声明一种类型的变量并将指向另一种类型函数的指针赋值给它。

首先,让我们修复一半的代码:

由于fcn_ptr是一个指向成员函数的指针,它的定义需要是:

double (Object::*fcn_ptr)(const double &) = NULL;

则构造函数中的强制转换无效。您试图将指向成员函数的指针强制转换为指向自由函数的指针。去掉石膏

Object() : fcn_ptr(&Object::fcn_default)
{}

最后,当您调用fcn_ptr时,您不能简单地凭空变出它。它是Object的数据成员,所以您需要一个类的实例来访问fcn_ptr。命名为:

(test1.*(test1.fcn_ptr))(2)

进行所有这些更改,一半的代码将编译并产生正确的结果。现场演示


另一半,由于前面提到的原因,您尝试将指向自由函数的指针赋值给fcn_ptr仍然不会工作。解决这个问题的方法是使用std::function代替函数指针。

class Object{
    public:
        Object() : fcn_ptr(std::bind(&Object::fcn_default, this, std::placeholders::_1))
        {}
        std::function<double(double const&)> fcn_ptr;
    private:
        double fcn_default(const double &phit){
            return 3.2+phit;
        }
};

然后使用:

cout << (test1.fcn_ptr)(2) << endl;
test2.fcn_ptr = &fcn_mod;
cout << (test2.fcn_ptr)(2) << endl;

现场演示

您没有一个具有"函数指针的函数"的类,而是具有函数指针的数据成员的类。这是一个重要的区别,因为函数不会接收 This 指针,也不能访问受保护成员或私有成员。

你已经正确地声明了函数指针,但是你需要使用.fcn_ptr而不是.*fcn_ptr。我相信这足以解决你的问题。

请注意,你正在使用旧的C风格的函数指针语法。你可能想学习c++函数指针的替代品,包括std::function .