@cocoatomo
Python との出会い: 仕事で Jython
こんな感じらしいっす.
c.f. http://en.wikipedia.org/wiki/Object-oriented_programming#Fundamental_concepts_and_features
→ 何はともあれ例をば...
Python で書いたこんなクラス
class Rect(object):
def __init__(self):
self.height = 0
self.width = 0
def rotate(self):
self.height, self.width = \
self.width, self.height
C だとまず構造体を書く
struct rect {
int height;
int width;
void (*rotate)(struct rect *);
};
→ 次はメソッド定義
void rect_init(struct rect *self)
{
self->height = 0;
self->width = 0;
self->rotate = *rect_rotate;
}
void rect_rotate(struct rect *self)
{
int tmp = self->height;
self->height = self->width;
self->width = tmp;
}
クラスを使う側のコードはこんな感じ
rect = Rect()
rect.height = 3
rect.width = 4
print('height: {0.height}, width: {0.width}'.format(rect))
rect.rotate()
print('height: {0.height}, width: {0.width}'.format(rect))
C だとこんな感じ
int main(void)
{
struct rect r;
rect_init(&r);
r.height = 3;
r.width = 4;
printf("height: %d, width: %d\n", r.height, r.width);
r.rotate(&r);
printf("height: %d, width: %d\n", r.height, r.width);
return 0;
}
完全なソースコードはここにあります.
→ C では無理
→ ヘッダファイル と static function で file scope を実現
→ dynamic dispatch が無いので無理
→ 構造体で Decorator パターン (後で詳しく)
→ 関数の第 1 引数を this や self にして自分自身を入れるルールにする. あれ? どこかで……
→ 構造体
→ 構造体オブジェクト
→ 構造体メンバー (関数ポインタ)
→ 無し
→ 継承で実現
ということで継承を詳しく見よう. 継承は入れ子になった構造体を上手く利用している.
メモリ配置はだいたいこんな感じ
<--- struct int_long --->
+--------+----------------+
|<- a -->|<----- b ------>|
+--------+----------------+
<-int -> <--- long ----->
struct base {
int basic_field;
};
struct extended {
struct base base;
int extended_field;
};
int main(void)
{
struct base *base_obj;
struct extended *obj = malloc(sizeof(struct extended));
// 省略...
base_obj = (struct base *) obj;
}
<---------- struct extended -------->
<- struct base ->
+-----------------+--------------------+
|<- basic_field ->|<- extended_field ->|
+-----------------+--------------------+
↓
CAST (struct base *)
↓
<- struct base ->
+-----------------+
|<- basic_field ->|
+-----------------+
完全なソースコードはここにあります. https://gist.github.com/972214
基底クラスを見ていこう.
/* Include/object.h */
/* 実際には PyObject の中には何も無いが,
* 全ての Python オブジェクトへのポインタは
* PyObject* にキャストできる.
* これは手作業による継承だ.
* 同様に不定サイズを持つ
* Python オブジェクトへのポインタは
* PyVarObject* にキャストできる.
*/
typedef struct _object {
定義はこんな感じ.
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt; // 参照カウンタ用
struct _typeobject *ob_type; // メソッドの塊
} PyObject;
メソッド部分はどうなってるのか?
/* Include/object.h */
typedef void (*destructor)(PyObject *);
typedef int (*printfunc)(PyObject *, FILE *, int);
// メソッドの塊
typedef struct _typeobject {
/* Methods to implement standard operations */
destructor tp_dealloc;
printfunc tp_print;
// 以下続く...
} PyTypeObject;
dict の実装を見て行く
/* Include/object.h */
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD PyObject ob_base;
/* Include/dictobject.h */
// dict 型の定義
typedef struct _dictobject PyDictObject;
struct _dictobject {
PyObject_HEAD // この中に PyTypeObject がある
// dict 独自のメンバー ...
};
/* dictobject.c */
PyTypeObject PyDict_Type = {
// dict 用のメソッドがたくさん...
mapp_methods, /* tp_methods */
// ...
};
PyObject *
PyDict_New(void)
{
// PyDict_Type を使ってオブジェクトを作っている...
mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
// ...
}
/* Include/objimpl.h */
#define PyObject_GC_New(type, typeobj) \
( (type *) _PyObject_GC_New(typeobj) )
/* Module/gcmodule.c */
// ようやくそれっぽいところに
PyObject *
_PyObject_GC_New(PyTypeObject *tp)
{
PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp));
if (op != NULL) // 型情報を使って初期化
op = PyObject_INIT(op, tp);
return op;
}
/* Objects/object.c */
PyObject *
PyObject_Init(PyObject *op, PyTypeObject *tp)
{
if (op == NULL)
return PyErr_NoMemory();
/* Any changes should be reflected in PyObject_INIT (objimpl.h) */
Py_TYPE(op) = tp; // 型情報を代入している!
_Py_NewReference(op);
return op;
}
/* Include/object.h */
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
/* Objects/abstract.c */
// __getitem__ の実装
PyObject *
PyObject_GetItem(PyObject *o, PyObject *key)
{
PyMappingMethods *m;
// ...
m = o->ob_type->tp_as_mapping;
if (m && m->mp_subscript)
return m->mp_subscript(o, key);
// ...
}
メソッドの塊 PyDict_Type を定義して, それを PyObject に入れて dict オブジェクトを作っている.