home link download back number special issue

HMDT - Special Issue / CoreFoundation の秘密 / Base Services - CoreFoundation のオブジェクト指向


- Base Services -
CoreFoundation のオブジェクト指向

CoreFoundation は、すべて C で書かれているライブラリだけど、オブジェクト指向的な設計になっているんだ。ほほぅ、C でオブジェクト指向?なにを持ってオブジェクト指向ってのは立場によって変わるけど、ここでは実装している仕組みのうち、カプセル化と多態性について見てみるぜ。

ちなみに、CoreFoundation では「クラス」っていう単語を避けているんだ。これを使うと混乱を招くからな。その代わり、オブジェクトやインスタンスって言葉を使う。

カプセル化

カプセル化ってのは、オブジェクトの中身が見えなくて、提供されている API を使ってアクセスすること。C++ とかでは、メンバ変数を private にすることで、言語レベルで実現しているんだ。Objective-C では、基本的にインスタンス変数にアクセスできない(できちゃうけど)。

CoreFoundation では、opaque type っていう技法を使って実現してるんだ(opaque type は日本だと不定形型かな)。これは、構造体の定義をヘッダで公開しない。その代わり、必要な操作は関数を通してやる、っていうものだ。

例として、CFArray を見てみよう。CFArray オブジェクトを表す CFArrayRef は、こう定義されてる。

CoreFoundation/Collections.subproj/CFArray.h
typedef const struct __CFArray * CFArrayRef;

なるほど。構造体 __CFArray のポインタだ。じゃ、__CFArray の定義は、、、ないぜーっ!見当たらないぞ!これじゃ、構造体の値を見れないじゃないか。と、いうのが opaque type。直接値をさわる代わりに、関数を使うんだ。たとえば、CFArrayGetValueAtIndex() とか。これは指定したインデックスの値を取る関数ね。こんな感じでカプセル化を実現しているんだ。

(実際には、この記事の後の方で見るように、CoreFoundation のソースが公開されているから、定義を見ることはできる。それで無理矢理キャストしてやれば、直接値をいじれる。でもこれをやると、バージョンが上がって実装が変わると動かなくなるから、やめた方がいい)

関数の多態性

CoreFoundation では、すべてのオブジェクトを CFTypeRef っていう型で受けることができるんだ。ま、Objective-C の id みたいなものか。で、CoreFoundation には、この CFTypeRef を引数に受ける関数があるんだ。たとえば、CFEqual() とか、CFHash() とか。

CoreFoundation/Base.subproj/CFBase.h
CFBase.h
CF_EXPORT
Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2);
CF_EXPORT
CFHashCode CFHash(CFTypeRef cf);

こういう汎用的な型に対応する関数では、渡されたオブジェクトによって、処理が変わるんだ。たとえば、CFHash() に、CFArrayRef が渡されれば CFArray のハッシュ関数を、CFStringRef が渡されれば CFString のハッシュ関数が呼ばれることになる。API 的には CFTypeRef で渡されるのに、いろんなオブジェクトの関数が呼ばれる。これが、関数の多態性だ。

さて、ここまではデザイン。実際にこれを実装するにはどうするか?端的に言うと、型の動的判別と、型に応じた関数を呼び出す仕組みがあればいい。この実装については次の章で。


Home | Link | Download | Back Number | Speciall Issue

mailto: mkino@xd5.so-net.ne.jp

HMDT