|
HMDT - Special Issue - Objective-C++ |
|
以下のドキュメントは、Mac OS X 10.1 Objective-C++ Release Notes を翻訳したものです。Mac OS X 10.1 での Objective-C++ の話です。 |
Mac OS X Developer Tools 10.1 Release Notes:Objective-C++Objective-C++ って何?Mac OS X 10.1 は、GCC の Mac OS X バージョンに Objective-C++ 機能を搭載したぜ!Objective-C++ では、C++ と Objective-C のコードを、同じファイルで、自由にまぜて使うことができるんだ。Objective-C++ を使えば、C++ のコードから直接 Objective-C のオブジェクトを呼ぶことができるし、Objective-C のオブジェクトから C++ のコードを呼ぶこともできるんだ。つまり、Objective-C++ は、Cocoa アプリケーションから直接 C++ のクラスライブラリを呼べるし、C++ アプリケーションから Cocoa や Foundation を呼べるんだ。 Objective-C++ ってのは、C++ の機能を Objective-C に付け加えるものじゃないんだ。逆に C++ に Objective-C の機能を付け加えるわけでもないよ。たとえば、C++ のオブジェクトを呼ぶのに Objective-C の構文は使えないし、Objective-C にコンストラクタやデストラクタを付け加えることもできない。あと、キーワード this と self を交換することもできない。C++ のクラスは Objective-C のクラスから継承することできないし、その逆もそうだ。 Objective-C++ ファイルの拡張子は .mm だ(つまり file.mm って感じね)。歴史的な理由から、コンパイラは .M(大文字の M)で終わるファイルも、Objective-C++ のソースとして扱うよ。これらの拡張子を持つファイルは、-x オプションを指定していなくても、Objective-C++ ソースファイルとみなされるんだ。Project Builder 1.1 は、そんなファイルを読み込んだら、ちゃんと適当なシンタックス・カラーリングをするぜ。 Objective-C++ のコンパイラは Mac OS X 10.1 の新機能なんだけど、コンパイルされたコードは、すべてのバージョンの Mac OS X で動くぜ。昔のやつでもオッケーだ。 じゃ、この後の文章は、Objective-C にも C++ の文法にも詳しい人向けだ。この 2 つの言語のインタラクションについて話すぜ。
C++ と Objective-C をまぜるObjective-C++ は、きみが期待してる通りに動くぜ!両方のクラスをさすポインタを使うことができる。インスタンス変数(Objective-C)と、メンバ変数(C++)ね。あと、メソッド(Objective-C)も、メンバ関数(C++)も、両方の言語から呼ぶことができる。両方の言語で、オブジェクトへのポインタってのは、つまるところ、ただのポインタだからね。どこでも使うことができるんだ。たとえば、Objective-C のオブジェクトを C++ クラスのデータメンバとして使うことができるし、C++ オブジェクトのポインタと参照を Objective-C のインスタンス変数として使うことができる。次のコードみたいに。
C の構造体を Objective-C の interface で使うように、C++ のクラスを使えるんだ。C の構造体のように、Objective-C interface の中の C++ クラスは、グローバルなスコープなんだ。Objective-C のクラスでネストされるわけじゃないからね(これって ANSI C が、C++ じゃなくて、ネストされた構造体を取り扱うのと同じだね)。 あと、条件コンパイルするために、Objective-C++ コンパイラは、__cplusplus と __OBJC__ を define しているんだ。それぞれ C++ と Objective-C 用にね。
Objective-C++ 言語の制限Objective-C++ ってのは、Objective-C と C++ を混ぜ合わせるのに最適でしょ。どっちかの言語で書かれたライブラリやフレームワークから、もう 1 つの言語のやつを呼び出すための、ブリッジになろうとしてるんだ。その両方の言語の合わせ方は、いろんな方法があるけれど、いくつかのやり方は Objective-C++ コンパイラによって禁止されてるんだ。これら制限は、この後のセクションに詳しく書いてあるけど、2 つの主要な理由があるんだ:
Objective-C++ プログラムは、コンパイルされて実行するとき、2 つの言語の実行環境とインタラクトするんだ。とうぜん Objective-C と C++ ね。こいつらは、2 つ別々なだけでなく、お互いに相手のことなんか気にしないんだ。Objective-C の実行環境は、C++ オブジェクトの、ストレージやリンケージとか知らないんだ。逆もいっしょ。C++ 実行環境は、Objective-C のオブジェクトのことなんか、知らない。こういう、どうやってオブジェクトを作るか、っていうことでは、片方の実行環境だけでは限界があるんで、もう片方の実行環境も使うんだ。 Objective-C との一貫性を残すために、Objective-C の制限は、Objective-C++ にも受け継がれているんだ。たとえば、Objective-C では、宣言のネストを禁じているので、Objective-C++ でもそうなってる。Objective-C++ は 2 つの言語のコンビネーションなんだけども、文法や意味を拡げるものじゃないんだ。 C++ と Objective-C のクラス階層は、別々じゃないとだめObjective-C++ では、Objective-C から C++ のクラスを継承することはできない。また、C++ から Objective-C のクラスを継承することもできないんだ。
Objective-C のオブジェクトは動的に型付けられて、C++ は、主に、静的に型付けられる。実行環境のポリモーフィズムのおかげでね。つまり、2 つの言語のオブジェクトモデルは、直接にはコンパチブルじゃないんだ。もっというと、Objective-C と C++ のオブジェクトのレイアウトは、お互いに互換性がないんだ。これは、一般的には、C++ と Objective-C 両方の立場から見て妥当なオブジェクトを作ることは、不可能なんだ。だから、クラス階層は、まぜることができないんだ。 Objective-C の宣言は、ファイルスコープにないといけないObjective-C のクラスやプロトコルを、C の構造体や(これは Objective-C と同じだね)、C++ のクラスや、C++ のネームスコープの中に入れてはいけない。すべての Objective-C の宣言は、ファイルスコープにないといけないんだ。
Objective-C は、ネストされたネームスコープや、宣言のネストがないから、Objective-C++ でもできないんだ。 C++ のネームスペースは、Objective-C の宣言の中に入れられらない同様に、C++ のネームスペースを Objective-C の宣言の中には入れられないんだ。
Objective-C には、ネストされたネームスペースがないから、Objective-C 宣言の中には、他のネームスペースを入れられないんだ。 Objective-C 宣言の中の C++ クラス宣言は、ファイルスコープに押し込まれるObjective-C++ では、Objective-C 宣言の中に、C++ クラス宣言を埋め込むことができるんだ。
Objective-C の中の C++ クラスは、自動的にファイルスコープになることに気をつけてくれ。これは、Objective-C が、C の構造体を扱うやり方といっしょだね。 すべての C++ のクラスが、Objective-C のインスタンス変数になるわけじゃないよObjective-C は、C の構造体を、インスタンス変数として使えるよね。Objective-C 宣言の中にあろうが、なかろうが。
同じようにするために、Objective-C++ は、C++ のクラスをインスタンス変数として使えるように、がんばってみるんだ。これは、C++ のクラス(とその親クラス)が、仮想関数を持たないなら、できるんだ。もし仮想関数があったら、その C++ のクラスは、Objective-C のインスタンス変数として使えないよ、きっと。
C++ で仮想関数を使うと、初期化するときに、仮想関数テーブルが必要になるんだ。だけど、Objective-C 実行環境は、C++ のオブジェクトモデルを知らないから、そんな初期化の仕方はしらないよ、きっと。 もし仮想関数がないとしても、C++ のオブジェクトをインスタンス変数として使うのは、潜在的な問題があるよ。Objective-C の実行環境が C++ オブジェクトを初期化できないように、C++ のコンストラクタとデストラクタ(仮想関数であろうがなかろうが)を、呼び出すことができないんだ。だから、C++ のクラスが、ユーザが定義したコンストラクタやデストラクタを持っていたとしても、そいつらを呼び出さないよ、きっと。Objective-C++ コンパイラは、そんな時は、警告を出すよ。 C++ のオブジェクトは、Objective-C のオブジェクトをインスタンスとして持たないよ同様に、Objective-C のクラスのインスタンスを、C++ のクラスに埋め込んだり、C++ の new や delete を使ってアクセスすることは、できないよ。
もう一度言うけど、これは Objective-C と C++ のオブジェクトモデルが違うせいなんだ。あと、Objective-C のオブジェクトを、ファイルスコープや、スタックに作ることも禁止されてるから、気をつけてくれ。これは、Objective-C のコンパイラと同じだし、Objective-C のオブジェクトは、ヒープの上に作られるようにデザインされてる、ってことに関係してるんだ(Objective-C のオブジェクトのサイズは、[[... alloc] init:...] で返ってくるけど、これは初期化のパラメータで変わるんだ)。(訳注:つまり、コンパイル時に決定することができない。だから、スタックにとれない) これは、Objective-C のオブジェクトは、ポインタ経由でしかアクセスできない、ってことだ。だけど、C++ で、“ラッパークラス”を作って、まるで C++ のクラスのように、インスタス作成をすることができるよ。
Objective-C とテンプレートObjective-C のクラスやプロトコルやカテゴリは、C++ のテンプレートの内部で宣言することはできないし、C++ のテンプレートは、Objective-C の @interface や @protocol やカテゴリの中で宣言できないよ。 Objective-C のクラスは、テンプレートのパラメタになれないけど、ポインタだったら、オッケーだ。 Objective-C と例外処理Objective-C で使われる NSException の例外モデルは、C のライブラリである、setjmp と longjmp をベースにしてるんだ。NSException が発生して、そのときスタック上に C++ のオブジェクトがあって、それが setjmp と NS_HANDLER の間にあったとしたら、その C++ のオブジェクトのデストラクタは呼ばれないんだ。すべての スタックベースの C++ のオブジェクトのデストラクタが呼ばれることを保証するには、Objective-C の例外を、できるかぎり catch しようとして、C++ の例外に翻訳してやる必要があるんだ:
C++ の例外を使うなら、Objective-C のオブジェクトを release しなくてはいけないことに、気をつけてくれ。そうじゃないと、メモリリークするよ。
C ヘッダをインクルードする古い Objective-C++ コンパイラ(Mac OS X 10.0 より前のね)は、extern "Objective-C" を使ってたんだ。レガシーな Objective-C ヘッダは、C++ のキーワードを使ってたんで(いちばん重要なのは class とか)、それを取り扱うためにね。いまのコンパイラは、extern "C" と extern "Objective-C" を、交換可能で使えるんだ(前者の方が後者より好ましいかな)。 文法的なあいまいさと、コンフリクトの可能性<objc/objc.h> で、いくつかの id が定義されてるんだ。すべての Objective-C と Objective-C++ プログラムは、これを include しないといけないんだ:
Objective-C のメソッドの中では、コンパイラが self とか super とかを事前に定義するんだ、C++ の this みたいなやつね。でも、C++ の this とは違って、self と super はキーワードじゃないんだ。Objective-C のメソッドの外では、普通の id のように使われるんだ。 protocol のパラメータリストの中では、5 つの文脈に依存するキーワード(oneway、in、out、inout、bycopy)が、あるんだ。これらは、他の文脈では、キーワードじゃないんだ。 Objective-C プログラマの立場から見ると、C++ には、新しいキーワードが加えられてるんだ。下に書いてあるみたいに。それらは、Objective-C のセレクタの名前として使えるんだ。だから、そんなにシビアなことじゃないよね。でも、型の名前としては使えないんだ。たとえば、class は C++ のキーワードなんだけど、NSObject メソッドのクラスは、まだ使えるんだ:
だけど、キーワードなんだから、class を変数の名前として使うことはできないんだ:
C++ のキーワードは、下のような感じ。 bool friend template Objective-C では、クラスとカテゴリの名前は、別々のネームスペースにあるんだ。だから、@interface foo と @interface(foo) は、同じソースコード上にいてもいいんだ。Objective-C++ でも、カテゴリが C++ クラスや構造体と、同じ名前を持ってもいいんだ:
プロトコルとテンプレートは、同じ文法で、別の意味をあらわすんだ:
実際上は問題ないはずだ。なぜなら、コンパイラは id をテンプレートの名前にすることを許さないからだ。 最後に、ラベルのあとに、グローバルの名前がくるときに、C++ は文法的な曖昧さがあるんだ。こんなやつ:
最初のコロンのあとに、スペースが必要だ。Objective-C++ にも、同じようなケースがうまれてしまってて、スペースが必要だ。
現在の Objective-C++ のリリースの既知のバグMac OS X 10.1 といっしょに出荷された Objective-C++ コンパイラは、テンプレート関数と、テンプレートクラスのメンバ関数から、Objective-C のメッセージを送ることができないんだ。
これを回避するには、Objective-C のメッセージ送信を、テンプレートじゃない C++ の関数に移して、テンプレートの中からそいつを呼ぶんだ。
将来のリリースで、このバグが直されることを、期待してるよ。
Objective-C++ コードのデバッグgdb の Objective-C++ コードのデバッグサポートは、完全じゃないんだ。gdb は、C++ と Objective-C を統合したパーサを持ってないんだ。っていうことは、gdb は C++ と Objective-C が混ざった式を評価できないんだ。たとえば、こういうコマンドは使えないんだ:
これは、デバッガは、.mm に対するデフォルトのパーサを、C++ を使うか Objective-C を使うか、選ばなくてはいけない、っていうことなんだ。純粋なデータレベルでは、Objective-C のオブジェクトは C++ よりシンプルだから、gdb は .mm の言語を C++ だと仮定するんだ。これは Project Builder の、Objective-C++ のデバッグを容易にしてくれるんだ。 だけど、これは、Objective-C のメソッドを gdb のコマンドラインから呼びたいときは、最初に言語を設定しないといけない、っていうことなんだ。たとえば、Objective-C のメソッドを呼びたいときは、次のようなコマンドを使うんだ:
もし Project Builder を使っているなら、言語を auto に戻すのを忘れないでくれ(上の例の 3 行目ね)。そうじゃないと、Project Builder は、次にコードをストップさせたとき、ローカル変数に値を入れるときに、問題が発生するよ。 |
|
Home | Link | Download | Back Number | Speciall Issue
|