高度な検索
Apple Developer Connection
Member Login ログイン | ご入会 ADC連絡先

< 前ページ次ページ >


C++ と Objective-C の併用

アップルの Objective-C コンパイラでは、C++ のコードと Objective-C のコードを同じソースファイルに混在させて記述することが可能です。このような Objective-C と C++ のハイブリッド言語は、Objective-C++ と呼ばれています。Objective-C++ を使えば、Objective-C アプリケーションから既存の C++ ライブラリを利用することができます。

Objective-C++ は Objective-C のクラスに C++ の機能を追加するものではなく、C++ のクラスに Objective-C の機能を追加するものでもありません。たとえば、Objective-C 構文を使用しての C++ オブジェクトの呼び出し、Objective-C オブジェクトへのコンストラクタやデストラクタの追加、キーワードの thisself の置き換え使用などを行うことはできません。クラス階層も異なります。C++ のクラスは Objective-C のクラスを継承できませんし、Objective-C のクラスも C++ のクラスを継承することはできません。さらに、複数言語の例外処理もサポートされていません。つまり、Objective-C コードでスローされた例外は C++ コードではキャッチできず、逆に、C++ コードでスローされた例外も Objective-C コードではキャッチできません。Objective-C の例外に関する詳細については、「例外処理とスレッド同期」を参照してください。

次のセクションでは、Objective-C++ で可能なことについて説明します。

このセクションの内容:

Objective-C と C++ の機能の混在
C++ の曖昧性と競合

Objective-C と C++ の機能の混在

Objective-C++ では、C++ コードと Objective-C メソッドのどちらの言語からでもメソッドを呼び出すことができます。どちらの言語でも、オブジェクトのポインタは単なるポインタであるため、どこでも使用できます。たとえば、Objective-C オブジェクトのポインタを C++ クラスのデータメンバとして含めることができ、C++ オブジェクトのポインタを Objective-C クラスのインスタンス変数として含めることができます。リスト 2-2 にこれを示します。

リスト 2-2 C++ と Objective-C インスタンスをインスタンス変数として使用

// HelloWorld.mm
#import 
class HelloWorld;
@interface PLog:NSObject {
 HelloWorld *ptr;
}
- (void)sayHello;
- (void)sayHi:(HelloWorld *)p;
- (id) init;
- (void) dealloc;
@end
class HelloWorld {
 id printLog;
public:
 HelloWorld(bool b) { if(b) printLog = [[PLog alloc] init]; }
 ~HelloWorld() { [printLog release]; }
 void sayHi() { printf(”Hi”); }
 void sayHello() { [printLog sayHi:this]; }
};
@implementation PLog
- (void) sayHello { NSLog(@"Hello, World!"); }
- (void) sayHi:(HelloWorld *)p { p->sayHi(); }
- (id) init { [super init]; ptr = new HelloWorld(false); return self; }
- (void) dealloc { delete ptr; [super dealloc]; }
@end

Objective-C インタフェースで C 構造体を宣言できるように、Objective-C インタフェースで C++ クラスを宣言することもできます。C 構造体と同様に、Objective-C インタフェースで定義した C++ クラスは、Objective-C のクラス内にネストされず、有効範囲がグローバルになります(これは、C++ ではなく、標準 C においてネストされた構造体定義の有効範囲がファイル単位になるのと同等です)。

言語に応じてコードの条件定義が行えるように、Objective-C++ コンパイラは、C++ および Objective-C 言語標準で規定されている、(それぞれ)__cplusplus__OBJC__ プリプロセッサ定数の両方を定義します。

前述したように、Objective-C++ では Objective-C オブジェクトから C++ クラスを継承できず、C++ オブジェクトから Objective-C クラスを継承することもできません。

class Base { /* ...*/ };
@interface ObjCClass:Base ...@end // エラー!
class Derived:public ObjCClass ...// エラー!

Objective-C と異なり、C++ のオブジェクトは静的に型定義されており、例外的なケースとして実行時にポリモーフィズムが利用できます。そのため、2 つの言語のオブジェクトモデルは、直接的には互換性がありません。さらに、より根本的な要素として、メモリ内における Objective-C と C++ オブジェクトのレイアウトは相互に互換性がありません。つまり、両言語に対して有効なオブジェクトインスタンスを作成するのは、一般的に不可能です。したがって、2 つのタイプの階層を混合することはできません。

Objective-C のクラス宣言の中で、C++ クラスを宣言することはできます。次のように、コンパイラは、グローバルなネームスペースで宣言されたものとして、このようなクラスを処理します。

@interface Foo {
 class Bar { ...} // OK
}
@end
Bar *barPtr; // OK

Objective-C では、(Objective-C 宣言の中で宣言されたかどうかに関係なく)C 構造体をインスタンス変数として使用できます。

@interface Foo {
 struct CStruct { ...};
 struct CStruct bigIvar; // OK
} ... @end

Objective-C++ も同様に、C++ クラスインスタンスをインスタンス変数として機能させることを目指しています。該当する C++ クラス(およびそのスーパークラスすべて)が仮想メンバ関数を定義しないかぎり、これは可能です。仮想メンバ関数がある場合、当該 C++ クラスは Objective-C のインスタンス変数として機能しません。

#import 
struct Class0 { void foo(); };
struct Class1 { virtual void foo(); };
struct Class2 { Class2(int i, int j); };
@interface Foo:NSObject {
 Class0 class0;    // OK
 Class1 class1;    // エラー!
 Class1 *ptr;      // OK―Foo の init から 'ptr = new Class1()' を呼び出し、
                    //  Foo の dealloc から 'delete ptr' を呼び出す
 Class2 class2;    // 警告 - コンストラクタを呼び出さない!
...
@end

C++ では、仮想関数を含むクラスの各インスタンスが、適切な仮想関数テーブルポインタを含む必要があります。しかし、Objective-C ランタイムは C++ オブジェクトモデルを知らないため、仮想関数テーブルポインタを初期化することができません。同様に、Objective-C ランタイムは、それらのオブジェクトの C++ コンストラクタまたはデストラクタに対して呼び出しを発行できません。C++ クラスにユーザ定義コのンストラクタやデストラクタがあっても、それらは呼び出されません。そのような場合、コンパイラは警告を発します。

Objective-C には、ネストされたネームスペースという概念がありません。C++ のネームスペースでは Objective-C クラスを宣言できず、Objective-C クラスでネームスペースを宣言することもできません。

Objective-C クラス、プロトコル、およびカテゴリは C++ テンプレート内で宣言できず、C++ テンプレートを Objective-C クラス、プロトコル、またはカテゴリの有効範囲内で宣言することもできません。

しかし、Objective-C クラスは、C++ テンプレートのパラメータとして使用することが可能です。また、Objective-C メッセージ式では、C++ テンプレートのパラメータを(セレクタとしてではなく)レシーバまたはパラメータとして使用することもできます。


C++ の曖昧性と競合

すべての Objective-C プログラムがインクルードする必要のある Objective-C ヘッダファイルには、いくつかの識別子が定義されています。これらの識別子は、idClassSELIMPBOOL です。

Objective-C メソッドの内部では、コンパイラは C++ のキーワード this と同様に、識別子 selfsuper を事前宣言します。しかし、C++ のキーワード this とは異なり、selfsuper はコンテキスト依存であるため、Objective-C メソッドの外部でも通常の識別子として使用できます。

プロトコル内のメソッドのパラメータリストには、さらに 5 つのコンテキスト依存キーワードがあります(onewayinoutinoutbycopy)。これらは、他のコンテキストではキーワードになりません。

Objective-C プログラマの観点からすると、C++ には新しいキーワードがかなり追加されています。それでも C++ キーワードは Objective-C セレクタの一部として使用できるため、影響はそれほど大きくありません。しかし、Objective-C クラスやインスタンス変数の指定に C++ キーワードを使用することはできません。たとえば、class が C++ キーワードであったとしても、依然として NSObject メソッド class を使用できます。

[foo class]; // OK

ただし、これはキーワードであるため、class を変数名として使用することはできません。

NSObject *class; // エラー

Objective-C では、クラスとカテゴリの名前は別々のネームスペースに属します。つまり、@interface foo@interface(foo) は、同じソースコード内に存在できます。Objective-C++ では、C++ クラスや構造体の名前と同じカテゴリを持つこともできます。

プロトコルとテンプレートの指定子は、異なる用途に同じ構文を使用します。

id foo;
TemplateType bar;

このような曖昧さを避けるために、コンパイラでは id をテンプレート名として使用することを認めていません。

最後に、次のように、ラベルの後にグローバル名を使用した式を続けた場合に、C++ の構文解釈上の曖昧さが生じます。

label: ::global_name = 3;

最初のコロンの後のスペースは必須です。Objective-C++ にも同様の場合があり、やはりスペースが必須です。

receiver selector: ::global_c++_name;


< 前ページ次ページ >


Last updated: 2003-09-16

製品のご購入・ご購入相談は、お気軽に アップルストアまで
0120-APPLE-1(0120-27753-1)

Copyright © 2004 Apple Computer, Inc.
All rights reserved. | Terms of use | Privacy Notice