Как да се справя с делегирането на goal-c от C++?

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

Подробности: Въпросните файлове:

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

menuHandler.h, menuHandler.mm - тези файлове съдържат (в момента празен) object-c клас, който възнамерявах да използвам като делегат

Първата ми мисъл беше, че мога просто да направя C++ класа делегат, но това очевидно не работи, тъй като C++ не разбира делегирането. Тогава си помислих, че ще направя отделен клас object-c като NSMenuDelegate и ще добавя негов екземпляр като член-обект към моя C++ клас. Тъй като успях да добавя други обекти на object-c като членове, реших, че това трябва да работи. Въпреки това, веднага щом включих заглавката за новия ми клас на goal-c в заглавния файл на клас C++, получих няколкостотин грешки относно „очакван неквалифициран идентификатор преди токена „@““ - от заглавните файлове на ябълката (NSValue.h , NSObject.h и т.н.) Така че очевидно това не работи, поне не както е. Получавам същия резултат, когато включвам ВСЯКАКВА заглавка на какао в моя заглавен файл на клас.

Тогава си помислих, че ще опитам декларация напред на класа goal-c (по този начин накарах другите обекти-c да работят). обаче и това не проработи - ако го декларирам като "class myClassName" получавам грешка относно повторното дефиниране на класа като различен тип символ (вероятно c++ клас срещу goal-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

Тогава си помислих, че ще опитам декларация напред на класа goal-c (по този начин накарах другите обекти-c да работят). обаче и това не проработи - ако го декларирам като "class myClassName" получавам грешка относно повторното дефиниране на класа като различен тип символ (вероятно c++ клас срещу goal-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