คุณสามารถผสม C ++ กับ Objective-C ได้หากคุณทำอย่างระมัดระวัง มีข้อแม้บางประการ แต่โดยทั่วไปแล้วสามารถใช้ผสมกันได้ หากคุณต้องการแยกมันออกจากกันคุณสามารถตั้งค่าฟังก์ชัน C wrapper มาตรฐานที่ให้ Objective-C อินเทอร์เฟซสไตล์ C ที่ใช้งานได้จากโค้ดที่ไม่ใช่ Objective-C (เลือกชื่อที่ดีกว่าสำหรับไฟล์ของคุณฉันได้เลือกชื่อเหล่านี้แล้ว สำหรับ verbosity):
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);
}
ฟังก์ชัน wrapper ไม่จำเป็นต้องอยู่ใน.m
ไฟล์เดียวกันกับคลาส Objective-C แต่ไฟล์ที่มีอยู่จะต้องคอมไพล์เป็นโค้ด Objective-Cความต้องการที่จะรวบรวมเป็นรหัสส่วนหัวที่ประกาศฟังก์ชัน wrapper จะต้องรวมไว้ในโค้ด CPP และ Objective-C
(หมายเหตุ: หากไฟล์การใช้งาน Objective-C ได้รับส่วนขยาย ".m" จะไม่เชื่อมโยงภายใต้ Xcode ส่วนขยาย ".mm" บอกให้ Xcode คาดว่าจะมีการรวมกันของ Objective-C และ C ++ นั่นคือ Objective-C ++ )
คุณสามารถใช้ข้างต้นในลักษณะเชิงวัตถุโดยใช้สำนวน PIMPLสำนวนการนำไปใช้แตกต่างกันเพียงเล็กน้อย ในระยะสั้นคุณวางฟังก์ชัน wrapper (ประกาศใน "MyObject-C-Interface.h") ภายในคลาสที่มีตัวชี้โมฆะ (ส่วนตัว) ไปยังอินสแตนซ์ของ MyClass
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
สังเกตว่าวิธีการ wrapper ไม่ต้องการตัวชี้โมฆะในอินสแตนซ์ของ MyClass อีกต่อไป ตอนนี้เป็นสมาชิกส่วนตัวของ 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 คุณสามารถสร้างอินสแตนซ์ MyClass ในตัวสร้างของ MyClassImpl ได้ แต่โดยทั่วไปแล้วไม่ใช่ความคิดที่ดี อินสแตนซ์ 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." );
}
}
ตอนนี้คุณเข้าถึงการโทรไปยัง MyClass ผ่านการใช้งาน MyClassImpl แบบส่วนตัว แนวทางนี้อาจเป็นประโยชน์หากคุณกำลังพัฒนาแอปพลิเคชันแบบพกพา คุณสามารถเปลี่ยนการใช้งาน MyClass กับแพลตฟอร์มที่เฉพาะเจาะจงไปยังแพลตฟอร์มอื่น ๆ ได้ ...