代码之家  ›  专栏  ›  技术社区  ›  souki

如何在静态函数中使用成员函数数组?

  •  0
  • souki  · 技术社区  · 6 年前

    我有个班,叫 Channel_thread . 您可以猜到,它的一个函数是线程的,在这个函数中,我想根据情况调用另一个成员函数。这就是我使用成员函数数组的原因。


    代码如下所示:

    通道螺纹.cpp:

    #include <boost/bind.hpp>
    #include "../include/Channel_thread.h"
    
    
    Channel_thread::Channel_thread(Event_queue<std::deque<char>> *_serverQueue, Event_queue<std::deque<char>> *_messageQueue)
    {
        serverQueue = _serverQueue;
        messageQueue = _messageQueue;
    
    }
    
    void Channel_thread::startThread()
    {
        isRunning = true;
    
        t = new boost::thread(boost::bind(&Channel_thread::start, this));
    }
    
    void Channel_thread::start(void *data)
    {
        auto *_this = (Channel_thread *)data;
        Message *messageReceived = NULL;
    
        while (_this->isRunning)
        {
            std::pair<std::string, std::deque<char>> p(_this->messageQueue->wait_and_pop());
            for (int index = 0; index != 4; index++)
            {
                if (_this->handlersIndexTab[index] == p.first)
                {
                    messageReceived = _this->handlersTab[index](p.second);
                    break ;
                }
            }
        }
    }
    
    Message *Channel_thread::channelSetupHandler(std::deque<char> bytes)
    {
    //Do stuff
    }
    
    Message *Channel_thread::channelStatusHandler(std::deque<char> bytes)
    {
    //Do stuff
    }
    
    Message *Channel_thread::channelCloseHandler(std::deque<char> bytes)
    {
    //Do stuff
    }
    
    Message *Channel_thread::streamSetupHandler(std::deque<char> bytes)
    {
    //Do stuff
    }
    

    槽钢螺纹H

    #include <boost/thread.hpp>
    #include "Event_queue.h"
    #include "Channel_setup.h"
    #include "Channel_status.h"
    #include "Channel_close.h"
    #include "Stream_setup.h"
    
    class Channel_thread {
    
        typedef Message *(Channel_thread::*fn)(std::deque<char>);
    
    
    public:
        Channel_thread(Event_queue<std::deque<char>> *, Event_queue<std::deque<char>> *);
    
        static void start(void *);
    
        void startThread();
    
        Message *channelSetupHandler(std::deque<char>);
        Message *channelStatusHandler(std::deque<char>);
        Message *channelCloseHandler(std::deque<char>);
        Message *streamSetupHandler(std::deque<char>);
    
    private:
        Event_queue<std::deque<char>> *messageQueue;
        Event_queue<std::deque<char>> *serverQueue;
    
        bool isRunning;
        boost::thread *t;
    
        fn handlersTab[4] = {channelSetupHandler, channelStatusHandler, channelCloseHandler, streamSetupHandler};
        std::string handlersIndexTab[4] = {"channel_setup", "channel_status", "channel_close", "stream_setup"};
    };
    

    我得到这个错误:

    /cygdrive/c/Users/foo/CLionProjects/Server_cpp/src/Channel_thread.cpp: In static member function 'static void Channel_thread::start(void*)':
    /cygdrive/c/Users/foo/CLionProjects/Server_cpp/src/Channel_thread.cpp:35:69: error: must use '.*' or '->*' to call pointer-to-member function in '_this->Channel_thread::handlersTab[index] (...)', e.g. '(... ->* _this->Channel_thread::handlersTab[index]) (...)'
                     messageReceived = _this->handlersTab[index](p.second);
    

    如您所见,我在数组中调用成员函数的方式似乎是错误的,可能是因为 static 上下文,我不知道,所以我的问题是:

    如何从静态函数调用存储在成员函数数组中的成员函数?

    事先谢谢。

    2 回复  |  直到 6 年前
        1
  •  1
  •   R Sahu    6 年前

    使用时有几个问题 _this->handlersTab[index](p.second); .

    1. 使用成员函数指针的语法与使用成员函数的语法不同。调用成员函数指针之前需要取消引用。给出成员函数指针, mfPtr ,要使用的语法是 (objectPtr->*mfPtr)(...) . 参见章节 指向成员函数的指针 https://en.cppreference.com/w/cpp/language/pointer 更多详情。

    2. 第二个问题是 handlersTab 不是 static 成员变量。要获得指向成员函数的指针,必须使用 _this->handlersTab .

    进行函数调用的一行程序是:

    messageReceived = (_this->*(_this->handlersTab[index]))(p.second);
    

    我建议用两行来简化它。

    fn handler = _this->handlersTab[index];
    messageReceived = (_this->*handler)(p.second);
    
        2
  •  1
  •   Michael Surette    6 年前

    如果使用C++ 17,最简单的解决方案是在函数头中使用STD::调用。

    std::invoke(&Channel_thread::handlersTab[index], this, p.second);
    

    确保扶手杆是静态的。handlersIndextab也应该是。

    根据具体情况,另一种方法是使用枚举而不是字符串作为消息,然后打开枚举并直接调用所需的方法。如果消息完全在您的控制之下,包括传输通道,这是最合适的。

    如果在消息中有一个描述性字符串很重要,我看到的另一种方法是打开消息的散列。 哈希必须是constexpr函数 这样您的case值就可以在编译时计算出来。用途:

    switch (hash(p.first))
    {
    case "channel_setup"_hash:
        channelSetupHandler(p.second)
        break;
    ...
    default:
        // error handling
    }
    

    使用这种方法的好处是

    • 直接调用所需方法
    • 不需要同步两个列表,实际上既不需要函数列表,也不需要查找列表。
    • 默认情况可用于处理错误消息
    • 更透明的代码
    • 易于扩展