6

私はObjective-Cクラスをインポートした小さなC++アプリケーションを持っています。これはObjective-C++ファイル.mmとして機能しますが、Objective-Cヘッダーを含む可能性のあるヘッダーを含むC ++ファイルは、適切なGCCドライバーの.mm拡張子に名前を変更する必要があります。

Objective-Cクラスの純粋なC++ラッパーを作成する方法はありますか、それとも、Objective-Cオブジェクトを何らかの方法で分離して、それらを個別にリンクすることはできますか?たぶん、Objective-Cクラスが小さなライブラリになったとしても、コンパイル時に静的に再リンクできますか?

問題は、このコードがクロスプラットフォームであり、通常はObjective-Cを使用しないシステム(つまりMacではない)でコンパイルするのがより難しいことです。プリプロセッサコマンドはWindowsまたはLinuxでのObjective-Cコードの実装を制限しますが、元のコードにはまだ.mm拡張子が付いており、GCCはコードをObjective-C++として扱います。

4

2 に答える 2

3

通常、不透明なポインタを使用し、C ++メソッドへの呼び出しをObjective-Cメソッドに転送するなどして、Objective-CクラスをC++クラスでラップするだけです。

そうすれば、ポータブルC ++ソースはObjective-Cに含まれるものを見る必要がなく、理想的には、異なるプラットフォーム上のラッパーの実装ファイルを交換するだけで済みます。

例:

// 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];
}

// ...
于 2010-02-09T05:41:37.463 に答える
2

はい、いくつかのトリックを知っていれば、どちらの方法でも簡単に可能です。

1)「id」タイプは実際にはプレーンCヘッダーで定義されています。したがって、次のことができます。

ヘッダー内:

#include <objc/objc.h>

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

実装(.mm):

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

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

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

2)ソースファイルに2つのうちの1つであるが、ObjC++ではないC++ / ObjC固有のコードが含まれている場合に、C ++/ObjC固有のコードを除外するために使用できるプリプロセッサ定数が2つあります。

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

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

注意してください。#ifdefを使用してivarまたは仮想メソッドを追加/削除することはできません。これにより、メモリレイアウトが異なる2つのクラスが作成され、アプリが非常に奇妙な方法でクラッシュします。

3)構造体の内容を宣言せずに、構造体へのポインタを使用できます。

ヘッダー内:

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

@end

実装ファイル(.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

これにより、ヘッダーは単純な標準CまたはObjCになりますが、実装ファイルは、ヒープ上のオブジェクトとしてそれぞれを作成/削除しなくても、呼び出されたすべてのivarのコンストラクタ/デストラクタを取得します。

これはすべてMac側だけですが、これは、ObjCのものをヘッダーから除外するか、少なくともC++移植性レイヤーのMac実装のクロスプラットフォームクライアントファイルから使用するときにコンパイルできることを意味します。

于 2010-02-14T23:27:05.773 に答える