Bạn có thể trộn C ++ với Objective-C nếu làm cẩn thận. Có một vài lưu ý nhưng nói chung chúng có thể bị trộn lẫn. Nếu bạn muốn giữ chúng riêng biệt, bạn có thể thiết lập một hàm trình bao bọc C tiêu chuẩn để cung cấp cho đối tượng Objective-C một giao diện kiểu C có thể sử dụng được từ mã không phải Objective-C (chọn tên tốt hơn cho tệp của bạn, tôi đã chọn những tên này cho độ dài):
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);
}
Hàm trình bao bọc không cần phải ở cùng .m
tệp với lớp Objective-C, nhưng tệp mà nó tồn tại cần được biên dịch dưới dạng mã Objective-C . Tiêu đề khai báo hàm trình bao bọc cần được bao gồm trong cả mã CPP và Objective-C.
(LƯU Ý: nếu tệp triển khai Objective-C có phần mở rộng là ".m", nó sẽ không liên kết theo Xcode. Phần mở rộng ".mm" cho Xcode biết mong đợi sự kết hợp giữa Objective-C và C ++, tức là Objective-C ++). )
Bạn có thể thực hiện những điều trên theo cách Hướng đối tượng bằng cách sử dụng thành ngữ PIMPL . Cách thực hiện chỉ khác một chút. Tóm lại, bạn đặt các hàm wrapper (được khai báo trong "MyObject-C-Interface.h") bên trong một lớp có con trỏ void (riêng tư) tới một phiên bản của 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
Lưu ý rằng các phương thức trình bao bọc không còn yêu cầu con trỏ void đến một thể hiện của MyClass; nó hiện là thành viên riêng của MyClassImpl. Phương thức init được sử dụng để khởi tạo một cá thể 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
Lưu ý rằng MyClass được khởi tạo bằng một lệnh gọi đến MyClassImpl :: init. Bạn có thể khởi tạo MyClass trong phương thức khởi tạo của MyClassImpl, nhưng đó thường không phải là một ý kiến hay. Cá thể MyClass bị hủy từ trình hủy của MyClassImpl. Như với việc triển khai kiểu C, các phương thức wrapper chỉ đơn giản là trì hoãn các phương thức tương ứng của 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." );
}
}
Giờ đây, bạn truy cập các cuộc gọi tới MyClass thông qua triển khai riêng của MyClassImpl. Cách tiếp cận này có thể có lợi nếu bạn đang phát triển một ứng dụng di động; bạn có thể chỉ cần hoán đổi việc triển khai MyClass với một ứng dụng cụ thể cho nền tảng khác ... nhưng thành thật mà nói, liệu đây có phải là cách triển khai tốt hơn hay không là vấn đề sở thích và nhu cầu.