Mex функция не может найти объект Matlab для обратного вызова - PullRequest
0 голосов
/ 12 февраля 2020

Я написал пример, в котором Matlab вызывает код C ++ (EventProducer), который должен вызывать метод объекта Matlab (EventConsumer).

Но когда я запускаю свой тест см. ниже), mexCallMATLAB вызывает ошибку, потому что кажется, что он не может получить объект EventConsumer Matlab:

Undefined function 'consumeEvent' for input arguments of type 'EventProducer'.

Следует отметить, что если вы замените «provider.run1 ();» от «продюсер.рун2 (потребитель)»; (где вы передаете объект EventConsumer), все работает хорошо!

Любой совет? Заранее спасибо.

Классы C ++:

class EventConsumer {
public:
    virtual ~EventConsumer() {}
    virtual void consumeEvent() = 0;
protected:
    EventConsumer() {}
};
class EventProducer {
public:
    EventProducer::EventProducer() : mConsumer(nullptr) {}
    virtual ~EventProducer() {}
    void setConsumer(EventConsumer* consumer) {
        mConsumer = consumer;
    }
    void run(EventConsumer* consumer = nullptr) {
        if (consumer != nullptr)
            consumer->consumeEvent();
        else if (mConsumer != nullptr)
            mConsumer->consumeEvent();
    }
private:
    EventConsumer* mConsumer;
};

Код Matlab:

classdef EventConsumer
    methods
        function this = EventConsumer(varargin)
        end
        function consumeEvent(varargin)
        disp('Matlab consumeEvent called')
      end
    end
end
classdef EventProducer < handle
    properties (SetAccess = private, Hidden = true)
        objectHandle; % Handle to the underlying C++ class instance
    end
    methods
      %% Constructor
      function this = EventProducer(varargin)
            this.objectHandle = EventProducer_mex('new', varargin{:});
      end
      %% Destructor
      function delete(this)
            EventProducer_mex('delete', this.objectHandle);
      end
    %% Other methods
    function setConsumer(this, consumer)
        EventProducer_mex('setConsumer', this.objectHandle, consumer);
    end
    function run1(this)
        EventProducer_mex('run1', this.objectHandle);
    end
    function run2(this, consumer)
        EventProducer_mex('run2', this.objectHandle, consumer);
    end
    end
end
producer = EventProducer();
consumer = EventConsumer();
producer.setConsumer(consumer);
producer.run1();
%% producer.run2(consumer);
delete(producer);

Файл Mex:

#include "../Class_Handle.hpp"
#include "EventProducer.h"
#include <iostream>
class MyEventConsumer : public EventConsumer {
public:
    MyEventConsumer(const mxArray* matlabConsumer) {
        mMatlabConsumer = matlabConsumer;
    }
    virtual ~MyEventConsumer() {}
    void consumeEvent() {
        std::cout << "C++ consumeEvent called" << std::endl;
        mxArray* prhs[1];
        prhs[0] = (mxArray*)mMatlabConsumer;
        mexCallMATLAB(0, NULL, 1, prhs, "consumeEvent");
    }
private:
    const mxArray* mMatlabConsumer;
};
// The mex entry point
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{   
    char fcn[64];
    if (nrhs < 1 || mxGetString(prhs[0], fcn, sizeof(fcn))) {
        mexErrMsgTxt("EventProducer_mex : First argument should be a function string less than 64 characters long.");
        return;
    }
    // Constructor
    if (! strcmp("new", fcn)) {
        if (nlhs != 1 || nrhs != 1) {
            mexErrMsgTxt("EventProducer_mex : 'new' function has wrong number of arguments.");
            return;
        }
        // Return a handle to a new C++ instance
        plhs[0] = convertPtr2Mat<EventProducer>(new EventProducer());
        return;
    }
    // Destructor
    if (! strcmp("delete", fcn)) {
        if (nlhs != 0 || nrhs != 2) {
            mexErrMsgTxt("EventProducer_mex : 'delete' function has wrong number of arguments.");
            return;
        }
        // Destroy the C++ object
        destroyObject<EventProducer>(prhs[1]);
        return;
    }
    // Other methods
    if (! strcmp("setConsumer", fcn)) {
        if (nlhs != 0 || nrhs != 3) {
            mexErrMsgTxt("EventProducer_mex : 'setConsumer' function has wrong number of arguments.");
            return;
        }
        // Get the C++ EventProducer object, then call setConsumer
        EventProducer* producer = convertMat2Ptr<EventProducer>(prhs[1]);
        if (producer == NULL) {
            mexErrMsgTxt("EventProducer_mex : 'setHandler' second argument should be a EventProducer class handle.");
            return;
        }
        MyEventConsumer* consumer = new MyEventConsumer(prhs[2]);
        producer->setConsumer(consumer);
        return;
    }
    // run1
    if (! strcmp("run1", fcn))
    {
        if (nlhs != 0 || nrhs != 2) {
            mexErrMsgTxt("EventProducer_mex : 'run1' function has wrong number of arguments.");
            return;
        }
        // Get the C++ EventProducer object, then call run
        EventProducer* producer = convertMat2Ptr<EventProducer>(prhs[1]);
        if (producer == NULL) {
            mexErrMsgTxt("EventProducer_mex : 'run1' second argument should be a EventProducer class handle.");
            return;
        }
        producer->run();
        return;
    }
    // run2
    if (! strcmp("run2", fcn)) {
        if (nlhs != 0 || nrhs != 3) {
            mexErrMsgTxt("EventProducer_mex : 'run2' function has wrong number of arguments.");
            return;
        }
        // Get the C++ EventProducer object, then call run
        EventProducer* producer = convertMat2Ptr<EventProducer>(prhs[1]);
        if (producer == NULL) {
            mexErrMsgTxt("EventProducer_mex : 'run2' second argument should be a EventProducer class handle.");
            return;
        }
        MyEventConsumer* consumer = new MyEventConsumer(prhs[2]);
        producer->run(consumer);
        return;
    }
    mexErrMsgTxt("Function not recognized.");
}
...