Функциональные указатели в Objective C - PullRequest
3 голосов
/ 13 мая 2011

Я наткнулся на следующий код при отладке. Мне удалось получить результат правильно, но я не понимал указатели функций, определенные здесь.

Здесь pNewMsgeFunc - псевдоним указателя функции tNewMsg, который создается внутри структуры stRsStruct.

RsMsg.h

typedef RsMsg* (*tNewMsg)(void);
tNewMsg    pNewMsgFunc;
typedef struct
{
    int         nMsgId;       
    NSString*     sAsciiName;       
    tNewMsg    pNewMsgFunc; // calls new for the particular message
} stRsStruct;

RsMsg.cpp

RsMsg(int uMessageId,tNewMsg pNewMsg,const char* szAsciiName,void* pData,
      size_t uDataSize)
{
 //intialisations
}

RsMsgDerived.h

#define DECLARE_NEWMSG(CssName,CssID)                   \
    static CssName* FromMsg(RsMsg* pMsg)                \
    {                                                   \
        return dynamic_cast<CssName*>(pMsg);            \
    }                                                   \
    static RsMsg* NewMsg()                              \
    {                                                   \
        return new CssName;                             \
    }                                                   \
    enum {ID = CssID};                                  \

Говорят, что в структуре pNewMsgFunc будет указывать на функцию NewMsg ().

Но я не мог понять, как это возможно, без инициализации tNewMsg с адресом

функция NewMsg (). Но этот код работает нормально. Нет других конструкторов, используемых для

инициализировать указатель функции адресом функции NewMsg ().

Event.cpp

#import "RsMsg.h"
#import "RsMsgDerived.h"

RsMsg* RsMsg::CreateMessage(REMOTE_MESSAGE_ID nMessageNumber)
{
    RsMsg*       pMsg = NULL;
    stRsStruct*  pMsgStruct;

    pMsg = pMsgStruct->pNewMsgFunc();    //Invoking the function pointer
}

Здесь, вызывая указатель на функцию, я вызываю статическую функцию NewMsg().

Но как эта функция вызывается как pNewMsgFunc(), ей не присваивается адрес NewMsg.

Мне нужно вызвать функцию NewMsg() через pNewMsgFunc(). Есть ли какие-либо изменения в вышеуказанном коде?

РЕДАКТИРОВАНИЕ:

Как реализовать тот же код в Objective C. Этот указатель на функцию вызывает функцию тип возвращаемого значения - класс. Так что указатели на функции могут быть реализованы в C как ее вызов функции, тип возвращаемого значения которой не может быть реализован в Objective C как функция c.

Ответы [ 4 ]

3 голосов
/ 13 мая 2011

Здесь pNewMsgeFunc - псевдоним имени указателя функции tNewMsg, который создается внутри структуры stRsStruct

Нет, это не так. tNewMsg - это имя, которое идентифицирует тип.

typedef RsMsg* (*tNewMsg)(void);

... но pNewMessageFunc является объектом этого типа.

Посмотри на это так. В этом коде:

typedef unsigned int uint;
uint n = 42;

n не является псевдонимом uint. Скорее, n является переменной типа uint.

Итак, pNewMessageFunc - это глобальная переменная (типа указатель на функцию, которая не принимает параметры и возвращает указатель на RsMsg), которую вы никогда не инициализируете.

1 голос
/ 13 мая 2011

Линия

tNewMsg    pNewMessageFunc

Не создает псевдоним, он объявляет место хранения типа tNewMsg. Я подозреваю, что вы неправильно ввели здесь свой код, поскольку объявление места хранения в заголовочном файле обычно приводит к дублированию мест хранения (т.е. ошибка компоновщика).

Это похоже на функцию конструктора

RsMsg(int uMessageId,tNewMsg pNewMsg,const char* szAsciiName,void* pData,size_t uDataSize)
{
    //intialisations
}

, который принимает tNewMsg и предположительно сохраняет его в данных экземпляра класса. Таким образом, ваша RsMsg::CreateMessage функция, вероятно, имеет доступ к инициализированному указателю функции.

0 голосов
/ 13 мая 2011

Первое, что меня поражает, это то, что вы выделяете указатель на stRsStruct, но используете его перед назначением памяти, на которую он указывает. Это неопределенное поведение, и вы можете ожидать, что все произойдет. Может случиться так, что из-за других вызовов случается попадание в стек, где другая функция имеет аналогичный указатель, который указывает на реальную память, и вы просто нажимаете что-то старое. Для того чтобы что-то происходило многократно, вы никогда не должны разыменовывать указатель, не указывая его на какой-то фактический блок памяти.

0 голосов
/ 13 мая 2011
RsMsg(int uMessageId,tNewMsg pNewMsg //this the function pointer as an arg to your initialization function, so I'm guessing the address of the correct function is passed here.

Только предположение, на самом деле не могу судить по вашему опубликованному коду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...