Как обрабатывать делегирование Objective-C из C ++?

Краткая версия: у меня есть Qt / C ++, к которому мне нужно добавить ограниченное количество кода Cocoa / Objective-C. Я изменил файл .cpp на файл .mm и добавил код / ​​объекты objective-c в указанный файл, и он компилируется и работает. Теперь мне нужен делегат для одного из созданных мною объектов - NSPopUpButton (или, точнее, его меню), если быть точным - и я застрял. Как я могу добавить делегата для этого объекта?

Подробности: рассматриваемые файлы:

reportwindow.h, reportwindow.cpp ПЕРЕИМЕНОВАН в reportwindow.mm - Это файлы, содержащие мою исходную реализацию на C ++ плюс некоторый код objective-c (откройте NSSavePanel, содержащий NSPopUpButton). reportwindow.h дополнительно включается в файл .cpp, если это имеет значение.

menuHandler.h, menuHandler.mm - эти файлы содержат (на данный момент пустой) класс objective-c, который я намеревался использовать в качестве делегата

Моя первая мысль заключалась в том, что я мог бы просто сделать класс C ++ делегатом, но это явно не работает, поскольку обычный C ++ не понимает делегирования. Затем я подумал, что создам отдельный класс objective-c как NSMenuDelegate и добавлю его экземпляр в качестве объекта-члена к моему классу C ++. Поскольку мне удалось добавить в качестве членов другие объекты objective-c, я решил, что это должно сработать. Однако, как только я включил заголовок для моего нового класса objective-c в файл заголовка класса C ++, я получил несколько сотен ошибок о «ожидаемом неквалифицированном идентификаторе перед токеном '@'» - из файлов заголовков Apple (NSValue.h , NSObject.h и т. Д.) Очевидно, это не сработало, по крайней мере, не как есть. Я получаю тот же результат, когда включаю ЛЮБОЙ заголовок какао в файл заголовка моего класса.

Затем я подумал, что попробую продвинуть объявление класса objective-c (именно так я заставил работать другие объекты objective-c). однако это тоже не сработало - если я объявляю его как "class myClassName", я получаю сообщение об ошибке переопределения класса как другого типа символа (предположительно, класс C ++ против протокола objective-c). Если я попытаюсь переслать объявление как @protocol myClassName, я получаю сообщение об ошибке «ожидаемый неквалифицированный идентификатор перед токеном @». Итак, как я могу заставить это работать?


person ibrewster    schedule 25.10.2011    source источник
comment
Вы переименовали этот конкретный файл cpp в mm?   -  person cli_hlt    schedule 25.10.2011
comment
Та, что связана с рассматриваемым заголовком, да.   -  person ibrewster    schedule 25.10.2011
comment
Второй путь - это путь, и, вероятно, единственный. Просто не стоит сдаваться после первой неудачной попытки. Предоставьте более подробную информацию, что включает в себя, может быть просто больше файлов .cpp, которые включают reportwindow.h.   -  person hamstergene    schedule 25.10.2011
comment
Что ж, я не совсем сдался после ПЕРВОЙ неудачной попытки - я просто не включил все кровавые подробности моей борьбы :-)   -  person ibrewster    schedule 25.10.2011


Ответы (4)


Хорошо, чтобы ответить на ваш вопрос:

reportwindow.h дополнительно включается в файл .cpp, если это имеет значение.

Это действительно имеет значение. Любая единица компиляции (в данном случае файл cpp), которая касается кода Objective-C, должна быть переименована в .mm или .m. Включение заголовка, который, в свою очередь, включает материал Objective-C в файл C ++, приведет к проблеме, заключающейся в том, что компилятор C ++ видит код Objective-C, который он не может обработать.

Переименование файла cpp в mm выберет опцию Objective-C во время компиляции (чего нет, когда файл назван cpp или c) и, следовательно, позволит компилировать материал с токенами Objective-C (в основном "@" в вашем случае) .

Альтернативой было бы не включать класс делегата Objective-C в ваш класс C ++, а вместо этого включать указатель на ваш класс C ++ в делегат Objective-C (т.е. реализовать его наоборот). Таким образом можно было расположить вещи так, чтобы код Objective-C не касался кода C ++.

Изменить: На самом деле, я бы предпочел второе предложение. Вот пример:

DelegateClass.h:

class MyCPPClassHandlingStuff;

@interface MyDelegateObject : NSObject <SomeDelegateProtocol> {
  MyCPPClassHandlingStuff *m_handlerInstance;
}

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance;

- (void) theDelegateProtocolMethod;

@end

DelegateClass.mm

#include "MyCPPClassHandlingStuff.h"

@implementation MyDelegateObject

- (id) initWithCPPInstance:(MyCPPClassHandlingStuff*)cppInstance
{
  self = [super init];
  if (self) {
    m_handlerInstance = cppInstance;
  }
  return self;
}

- (void) theDelegateProtocolMethod
{
  if (m_handlerInstance)
    m_handlerInstance->handleDelegateMethod();
}

@end

Ну и MyCPPClassHandlingStuff.h:

#ifndef __MyCPPClassHandlingStuff_H__
#define __MyCPPClassHandlingStuff_H__

class MyCPPClassHandlingStuff
{
public:
  MyCPPClassHandlingStuff();
  void handleDelegateMethod();
};

#endif /* __MyCPPClassHandlingStuff_H__ */

MyCPPClassHandlingStuff можно инициализировать из Objective-C, но вы не можете инициализировать какой-либо класс Objective-C из кода C ++ там. Если вам нужно использовать Objective-C в вашем коде C ++, вам придется скомпилировать его как Objective-C (т.е. использовать файл .mm). Я оставляю детали .cpp в качестве упражнения для читателя;)

person cli_hlt    schedule 25.10.2011
comment
Не могли бы вы также дать представление о реализации .cpp: P Как вы инициализируете MyDelegateObject из cpp. - person Aalok; 09.01.2015

Создайте класс Objective-C, чтобы удовлетворить протокол делегата, и делегируйте его вашему классу C ++. Проблема в том, что AppKit ожидает взаимодействия с объектами Objective-C, поэтому вам нужна прокладка для делегирования вашим объектам C ++. (Да, вы можете злоупотреблять во время выполнения, определяя указатель isa в своем классе C ++, чтобы сделать его несколько совместимым с объектами ObjC (до такой степени, что вы можете отправлять сообщения классам C ++), но не делайте этого. Это неприятно.)

Итак, сделайте прокладку, которая инициализируется вашим классом C ++, имеет это как ivar. Он должен реализовать интересующие вас методы делегата и передать их вашему классу C ++ понятным для него способом. Тада, готово.

person jer    schedule 25.10.2011

Затем я подумал, что попробую продвинуть объявление класса objective-c (именно так я заставил работать другие объекты objective-c). однако это тоже не сработало - если я объявляю его как "class myClassName", я получаю сообщение об ошибке переопределения класса как другого типа символа (предположительно, класс C ++ против протокола objective-c).

Почему бы не объявить его как @class myClassName?

person Luke    schedule 25.10.2011
comment
Я пробовал это, он выдавал ошибки об ожидаемом неквалифицированном идентификаторе перед символом '@'. Оказывается, Qt генерировал файл moc_ ‹filename› .cpp, который сбивал с толку. Переименование на .mm устранило проблему. - person ibrewster; 25.10.2011

Есть полезная информация о том, как настроить заголовки, чтобы их можно было использовать как из ObjC, так и из C ++ в Могу ли я отделить основную функцию и классы C ++ от подпрограмм Objective-C и / или C при компиляции и компоновке?

person uliwitness    schedule 12.02.2015