2010-02-09 21 views
6

Tôi có một ứng dụng C++ nhỏ mà tôi đã nhập các lớp Objective-C. Nó hoạt động như các tệp Objective-C++, .mm, nhưng bất kỳ tệp C++ nào bao gồm một tiêu đề có thể kết thúc bao gồm một số tiêu đề Objective-C phải được đổi tên thành phần mở rộng .mm cho các trình điều khiển GCC thích hợp.Tôi có thể tách các hàm và lớp chính của C++ khỏi các thường trình Objective-C và/hoặc C khi biên dịch và liên kết không?

Có cách nào để viết một trình bao bọc C++ thuần túy cho các lớp Objective-C hoặc tôi có thể tách các đối tượng Objective-C ra bằng cách nào đó và chỉ liên kết chúng một cách riêng biệt không? Có lẽ ngay cả khi các lớp Objective-C trở thành một thư viện nhỏ, tôi vẫn có thể liên kết lại một cách tĩnh tại thời gian biên dịch?

Vấn đề là mã này là nền tảng chéo và khó biên dịch hơn trên các hệ thống thường không sử dụng Objective-C (ví dụ: không phải máy Mac). Mặc dù các lệnh tiền xử lý hạn chế việc thực thi mã Objective-C trên Windows hoặc Linux, mã gốc vẫn có phần mở rộng .mm và GCC vẫn xử lý mã như Objective-C++.

Trả lời

3

Thông thường, bạn chỉ cần bọc các lớp Objective-C của mình bằng các lớp C++ bằng ví dụ: sử dụng opaque pointers và chuyển tiếp cuộc gọi đến phương thức C++ đến các phương pháp Objective-C.

Bằng cách đó, nguồn C++ di động của bạn không bao giờ phải xem bất kỳ Mục tiêu-C nào và lý tưởng là bạn chỉ phải trao đổi các tệp triển khai cho trình bao bọc trên các nền tảng khác nhau.

Ví dụ:

// c++ header: 
class Wrapper { 
    struct Opaque; 
    Opaque* opaque; 
    // ... 
public: 
    void f(); 
}; 

// Objective-C++ source on Mac: 
struct Wrapper::Opaque { 
    id contained; 
    // ... 
}; 

void Wrapper::f() { 
    [opaque->contained f]; 
} 

// ... 
+0

vì vậy sau đó sẽ cấu trúc Wrapper :: Opaque bao gồm 'OBJCClass * name = [[OBJCClass alloc] init]' và Wrapper :: f() sẽ gọi [name f] nếu nó được liên kết như vậy? –

+0

Có, bạn có thể cấp phát và khởi tạo lớp Objective-C chứa trong hoặc là hàm tạo 'Wrapper' hoặc' Opaque', bất cứ điều gì phù hợp với bạn và các phương thức lớp C++ sẽ chuyển tiếp các cuộc gọi đến lớp Objective-C của bạn. –

2

Vâng, đó là một cách dễ dàng có thể, cả hai cách, nếu bạn biết một vài thủ thuật:

1) "id" loại thực sự được định nghĩa trong một tiêu đề C đồng bằng. Vì vậy, bạn có thể làm như sau:

Trong tiêu đề của bạn:

#include <objc/objc.h> 

class MyWindow 
{ 
public: 
    MyWindow(); 
    ~MyWindow(); 
protected: 
    id  mCocoaWindow; 
}; 

Trong thực hiện của bạn (.mm):

#include "MyWindow.h" 
#include <Cocoa/Cocoa.h> 

MyWindow::MyWindow() 
{ 
    mCocoaWindow = [[NSWindow alloc] init]; 
} 

MyWindow::~MyWindow() 
{ 
    [mCocoaWindow release]; 
    mCocoaWindow = nil; 
} 

2) Có hai hằng số tiền xử lý, bạn có thể sử dụng để loại trừ C++/Mã đặc trưng của ObjC khi một tệp nguồn bao gồm chúng là một trong hai tệp, nhưng không phải là ObjC++:

#if __OBJC__ 
// ObjC code goes here. 
#endif /* __OBJC__*/ 

#if __cplusplus 
// C++ code goes here. 
#endif 

Chỉ cần cẩn thận, bạn không thể chỉ thêm/xóa ivars hoặc các phương thức ảo bằng #ifdef, điều này sẽ tạo ra hai lớp với các bố trí bộ nhớ khác nhau và làm cho ứng dụng của bạn gặp sự cố theo những cách rất lạ.

3) Bạn có thể sử dụng một con trỏ đến một cấu trúc mà không tuyên bố nội dung của nó:

Trong tiêu đề của bạn:

@interface MyCppObjectWrapper : NSObject 
{ 
    struct MyCppObjectWrapperIVars *ivars; // This is straight ObjC, no ++. 
} 

@end 

Trong tập tin thực thi của bạn (.mm):

struct MyCppObjectWrapperIVars 
{ 
    std::string myCppString1; 
    std::string myCppString2; 
    std::string myCppString3; 
}; 

@implementation MyCppObjectWrapper 

-(id) init 
{ 
    if((self = [super init])) 
    { 
     ivars = new MyCppObjectWrapperIVars; 
    } 

    return self; 
} 

-(void) dealloc 
{ 
    delete ivars; 
    ivars = NULL; 

    [super dealloc]; 
} 

@end 

Điều này sẽ làm cho tiêu đề của bạn tiêu chuẩn đơn giản C hoặc ObjC, trong khi tệp triển khai của bạn nhận các hàm tạo/hủy của tất cả các ivars được gọi mà không cần phải tạo/xóa từng đối tượng như một đối tượng trên ap.

Đây chỉ là mặt của Mac, nhưng điều này có nghĩa là bạn có thể giữ các thứ ObjC ra khỏi tiêu đề của bạn hoặc ít nhất là biên dịch khi được sử dụng từ các tệp khách hàng đa nền tảng của việc triển khai Mac của bạn Lớp di chuyển C++.

Các vấn đề liên quan