C++存储对对象自身函数的引用

C++ storing a reference to an objects own function

本文关键字:函数 引用 存储 对象 C++      更新时间:2023-10-16

问题

我正在尝试创建一种方法,根据C++类中用户给定的输入动态调用不同的函数。我尽量避免使用一堆if语句,因为这会给我的代码增加很多复杂性。我想做的是将引用存储在映射中,这样我就可以循环使用它并执行存储的函数。

当前设置

目前我已经完成了这项工作,但它使用了静态方法调用,我不喜欢这种调用,因为我必须设置一堆对方法所需内容的静态引用,或者对私有变量进行大量getter。我陷入了静止的地狱。

这是一些代码(我身上没有实际的代码,所以我重写了我认为我有的代码。有些语法可能是错误的,但我有它在我的测试机上编译和工作(

typedef void (*functocall)(void) funcRef;
class Installer {
    struct Step {
        QString id,
        QString message,
        funcRef func
    }
    enum INSTALL_TYPE {
        APP_INSTALL,
        FILESYSTEM_INSTALL
        BOTH_INSTALL,
        ...
    }
public:
    void addStep(QString id, QString message, funcRef func) {
        Step step;
        step.id = id;
        step.message = message;
        step.func = func;
    }
    void nextStep() {
        // calls next in the map
        m_steps[m_currStep].func();
        m_currStep++;
    }
    void run(INSTALL_TYPE type) {
        // Storing in a map lets me define the entire process for all install types in one method. Also can mix methods between processes if needed
        // Also using steps to keep track of overall progess (currStep / m_steps.size())
        // Also lets me show the user all of the steps that will occur for this install
        // Basically is for creating a progress bar on a web interface and sending it percentages and a message
        if(type == APP_INSTALL || type == BOTH_INSTALL)
        {
            addStep("upload", "Uploading files", &Installer::uploadAppFiles);
        }
        if(type == FILESYSTEM_INSTALL || type == BOTH_INSTALL)
        {
            addStep("upload", "Uploading files", &Installer::uploadFileSystemFiles);
            addStep("extract", "Uploading files", &Installer::extractTar);
        }
        if(type == APP_INSTALL || type == BOTH_INSTALL)
        {
            addStep("install", "Install app", &Installer::installAppFiles);
        }
        if(type == FILESYSTEM_INSTALL || type == BOTH_INSTALL)
        {
            addStep("install", "Install file system", &Installer::installFileSystemFiles);
        }
        addStep("cleanup", "Cleanup system", &Installer::cleanup);
        addStep("reboot", "Reboot system", &Installer::reboot);
    }
    static void uploadAppFiles() {
        ...
    }
    static void uploadFileSystemFiles() {
        ...
    }
    ... other static methods
private:
    QList<Step> m_steps;
    int m_currStep;
}

首选解决方案

我真正喜欢做的是在安装程序类中存储对非静态方法的引用。我只需要这个对象能够调用它自己的内部方法,这样我就可以确保这个对象永远存在。

我已经研究了std::函数,但无法使其工作,因为我没有c++11,我认为这是必需的我也不能使用boost::函数,因为我不想将boost添加到我的项目中。我已经在使用QT了,所以如果QT中有什么东西可以轻松做到这一点,我更喜欢它。

最初我是通过Javascript在客户端完成这一切的,这非常简单,我有点后悔把它移植到C++中,哈哈。

您只需要声明一个成员函数指针类型,该类型与普通函数指针具有不同的语法。此外,当通过成员函数指针调用成员函数时,显然必须提供对象。

//forward declare class
class Installer;
typedef void (Installer::*funcRef)(); // member function pointer
//            ^^^^^^^^^ <-- mentions the class it is a member of
class Installer {
    struct Step {
        QString id;
        QString message;
        funcRef func; // member function
    };
    enum INSTALL_TYPE {
        APP_INSTALL,
        FILESYSTEM_INSTALL,
        BOTH_INSTALL,
    };
public:
    void addStep(QString id, QString message, funcRef func) {
        Step step;
        step.id = id;
        step.message = message;
        step.func = func;
    }
    void nextStep() {
        // supply objects to member function pointer call
        // using this->*
        (this->*m_steps[m_currStep].func)();
    //   ^^^^ <- supplies the object the member is to be called on
        m_currStep++;
    }
    void run(INSTALL_TYPE type) {
        // Storing in a map lets me define the entire process for all install types in one method. Also can mix methods between processes if needed
        // Also using steps to keep track of overall progress (currStep / m_steps.size())
        // Also lets me show the user all of the steps that will occur for this install
        // Basically is for creating a progress bar on a web interface and sending it percentages and a message
        if(type == APP_INSTALL || type == BOTH_INSTALL)
        {
            addStep("upload", "Uploading files", &Installer::uploadAppFiles);
        }
        if(type == FILESYSTEM_INSTALL || type == BOTH_INSTALL)
        {
            addStep("upload", "Uploading files", &Installer::uploadFileSystemFiles);
//            addStep("extract", "Uploading files", &Installer::extractTar);
        }
        if(type == APP_INSTALL || type == BOTH_INSTALL)
        {
//            addStep("install", "Install app", &Installer::installAppFiles);
        }
        if(type == FILESYSTEM_INSTALL || type == BOTH_INSTALL)
        {
//            addStep("install", "Install file system", &Installer::installFileSystemFiles);
        }
//        addStep("cleanup", "Cleanup system", &Installer::cleanup);
//        addStep("reboot", "Reboot system", &Installer::reboot);
    }
    void uploadAppFiles() {
//        ...
    }
    void uploadFileSystemFiles() {
//        ...
    }
//    ... other static methods
private:
    QList<Step> m_steps;
    int m_currStep;
};

如果从QObject派生类,并将需要调用的函数放入"slots"部分,则可以使用QMetaObject::invokeMethod按名称调用它们。