신중하게 수행하면 C ++와 Objective-C를 혼합 할 수 있습니다. 몇 가지주의 사항이 있지만 일반적으로 혼합 할 수 있습니다. 별도로 유지하려면 Objective-C 개체에 비 Objective-C 코드에서 사용할 수있는 C 스타일 인터페이스를 제공하는 표준 C 래퍼 함수를 설정할 수 있습니다 (파일에 대해 더 나은 이름을 선택하고이 이름을 선택했습니다). 자세한 정보) :
MyObject-C-Interface.h
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
// This is the C "trampoline" function that will be used
// to invoke a specific Objective-C method FROM C++
int MyObjectDoSomethingWith (void *myObjectInstance, void *parameter);
#endif
MyObject.h
#import "MyObject-C-Interface.h"
// An Objective-C class that needs to be accessed from C++
@interface MyObject : NSObject
{
int someVar;
}
// The Objective-C member function you want to call from C++
- (int) doSomethingWith:(void *) aParameter;
@end
MyObject.mm
#import "MyObject.h"
@implementation MyObject
// C "trampoline" function to invoke Objective-C method
int MyObjectDoSomethingWith (void *self, void *aParameter)
{
// Call the Objective-C method using Objective-C syntax
return [(id) self doSomethingWith:aParameter];
}
- (int) doSomethingWith:(void *) aParameter
{
// The Objective-C function you wanted to call from C++.
// do work here..
return 21 ; // half of 42
}
@end
MyCPPClass.cpp
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
int MyCPPClass::someMethod (void *objectiveCObject, void *aParameter)
{
// To invoke an Objective-C method from C++, use
// the C trampoline function
return MyObjectDoSomethingWith (objectiveCObject, aParameter);
}
래퍼 기능 은 필요하지 않습니다.m Objective-C 클래스 와 동일한 파일 에있을 존재하는 파일 은 Objective-C 코드로 컴파일해야합니다 . 래퍼 함수를 선언하는 헤더는 CPP 및 Objective-C 코드 모두에 포함되어야합니다.
(참고 : Objective-C 구현 파일에 ".m"확장자가 지정되면 Xcode 아래에 링크되지 않습니다. ".mm"확장자는 Objective-C와 C ++, 즉 Objective-C ++의 조합을 예상하도록 Xcode에 지시합니다. )
다음을 사용하여 객체 지향 방식으로 위를 구현할 수 있습니다. PIMPL 관용구 . 구현은 약간만 다릅니다. 간단히 말해서, MyClass의 인스턴스에 대한 (개인) void 포인터가있는 클래스 안에 래퍼 함수 ( "MyObject-C-Interface.h"에서 선언 됨)를 배치합니다.
MyObject-C-Interface.h (PIMPL)
#ifndef __MYOBJECT_C_INTERFACE_H__
#define __MYOBJECT_C_INTERFACE_H__
class MyClassImpl
{
public:
MyClassImpl ( void );
~MyClassImpl( void );
void init( void );
int doSomethingWith( void * aParameter );
void logMyMessage( char * aCStr );
private:
void * self;
};
#endif
래퍼 메서드는 더 이상 MyClass의 인스턴스에 대한 void 포인터를 필요로하지 않습니다. 이제 MyClassImpl의 개인 멤버입니다. init 메소드는 MyClass 인스턴스를 인스턴스화하는 데 사용됩니다.
MyObject.h (PIMPL)
#import "MyObject-C-Interface.h"
@interface MyObject : NSObject
{
int someVar;
}
- (int) doSomethingWith:(void *) aParameter;
- (void) logMyMessage:(char *) aCStr;
@end
MyObject.mm (PIMPL)
#import "MyObject.h"
@implementation MyObject
MyClassImpl::MyClassImpl( void )
: self( NULL )
{ }
MyClassImpl::~MyClassImpl( void )
{
[(id)self dealloc];
}
void MyClassImpl::init( void )
{
self = [[MyObject alloc] init];
}
int MyClassImpl::doSomethingWith( void *aParameter )
{
return [(id)self doSomethingWith:aParameter];
}
void MyClassImpl::logMyMessage( char *aCStr )
{
[(id)self doLogMessage:aCStr];
}
- (int) doSomethingWith:(void *) aParameter
{
int result;
// ... some code to calculate the result
return result;
}
- (void) logMyMessage:(char *) aCStr
{
NSLog( aCStr );
}
@end
MyClass는 MyClassImpl :: init를 호출하여 인스턴스화됩니다. MyClassImpl의 생성자에서 MyClass를 인스턴스화 할 수 있지만 일반적으로 좋은 생각이 아닙니다. MyClass 인스턴스는 MyClassImpl의 소멸자에서 소멸됩니다. C 스타일 구현과 마찬가지로 래퍼 메서드는 단순히 MyClass의 각 메서드를 따릅니다.
MyCPPClass.h (PIMPL)
#ifndef __MYCPP_CLASS_H__
#define __MYCPP_CLASS_H__
class MyClassImpl;
class MyCPPClass
{
enum { cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING = 42 };
public:
MyCPPClass ( void );
~MyCPPClass( void );
void init( void );
void doSomethingWithMyClass( void );
private:
MyClassImpl * _impl;
int _myValue;
};
#endif
MyCPPClass.cpp (PIMPL)
#include "MyCPPClass.h"
#include "MyObject-C-Interface.h"
MyCPPClass::MyCPPClass( void )
: _impl ( NULL )
{ }
void MyCPPClass::init( void )
{
_impl = new MyClassImpl();
}
MyCPPClass::~MyCPPClass( void )
{
if ( _impl ) { delete _impl; _impl = NULL; }
}
void MyCPPClass::doSomethingWithMyClass( void )
{
int result = _impl->doSomethingWith( _myValue );
if ( result == cANSWER_TO_LIFE_THE_UNIVERSE_AND_EVERYTHING )
{
_impl->logMyMessage( "Hello, Arthur!" );
}
else
{
_impl->logMyMessage( "Don't worry." );
}
}
이제 MyClassImpl의 개인 구현을 통해 MyClass에 대한 호출에 액세스합니다. 이 접근 방식은 휴대용 응용 프로그램을 개발하는 경우 유용 할 수 있습니다. MyClass의 구현을 다른 플랫폼에 특정한 구현으로 교체 할 수 있습니다.하지만 솔직히 이것이 더 나은 구현인지 여부는 취향과 필요의 문제입니다.