2009-08-04 16 views
7

私は特に、Pythonなどのインタープリタ言語のコアを形成するオブジェクトの実装とは対照的に、C内から使用されることを意図したオブジェクトに興味があります。人々はCでオブジェクトを構築するためにどのような手法や戦略を使用しますか(C++ではありません)?

+1

私はいつも「オブジェクトベース」のCプログラミングスタイルを使用していましたが、これはC++の多くの方がずっと簡単です。なぜあなたはそれを使いたくないと思うのですか? –

+1

@ Neeil:理由がない場合、GObjectはありません。 Cのための多くの理由があります:旧式のプラットフォーム、protability、バイナリABI互換性、あなたは名前を付けます。 – EFraim

+0

@EFraim私はこれらの理由を十分に認識していますが、私は質問者の理由を聞いていました。 –

答えて

4

GObjectのようなライブラリ。

基本的に、GObjectは、不透明な値(整数、文字列)とオブジェクトを記述する一般的な方法を提供します(インタフェースを手作業で記述することにより、関数ポインタの構造としてC++のVTableに基本的に対応します)。あなたは、多くの場合、また、手実装してのvtableをIJG's実装で"COM in plain C"

+0

EFraim - 回答にGObject実装戦略を記述して、他の解決策のいくつかと比較することはできますか? – SetJmp

0

ルックのようにそのreference

で見つかりました。彼らは例外処理のためにsetjmp/longjmpを使用するだけでなく、vtableとすべてを持っています。非常に良い例を得るには十分に書かれた小さなライブラリです。

+0

DaleとFalainaが提案したような実装を使用しているかどうか知っていますか?それとももう少しダイナミックなものか? – SetJmp

+0

ええ、非常に似ています。 – cheez

9

私はこのような何かする傾向がある:

:FOOを使用するコードでは、次に

static void plugh(struct foo *, ...) { ... } 
static void blah(struct foo *, ...) { ... } 

static struct foo_ops foo_ops = { blah, plugh }; 

struct foo *new_foo(...) { 
    struct foo *foop = malloc(sizeof(*foop)); 
    foop->ops = &foo_ops; 
    /* fill in rest of *foop */ 
    return foop; 
} 

:これらの構造体の定義では

struct foo_ops { 
    void (*blah)(struct foo *, ...); 
    void (*plugh)(struct foo *, ...); 
}; 
struct foo { 
    struct foo_ops *ops; 
    /* data fields for foo go here */ 
}; 

を、コードの実装fooは次のようになります

struct foo *foop = new_foo(...); 
foop->ops->blah(foop, ...); 
foop->ops->plugh(foop, ...); 

このコードは、マクロまたはインライン関数で整理することができるので、Cのように見える

foo_blah(foop, ...); 
foo_plugh(foop, ...); 

あなたが「OPS」フィールドのための合理的に短い名前に固執する場合、単に元々示されたコードを書くことが特に冗長ではありません。

この手法は、Cで比較的単純なオブジェクトベースの設計を実装するには完全に適していますが、ではなく、では明示的にクラスを表す方法やメソッドの継承などを処理します。そのためには、GObjectのようなものが必要かもしれませんが、より複雑なフレームワークの余分な機能が本当に必要であることを確認することをお勧めします。

7

"オブジェクト"という用語の使用は少し曖昧ですので、私はあなたがオブジェクト指向プログラミングの特定の側面を達成するためにCを使う方法を尋ねていると思います。)

方法多型:

メソッドの多型は、典型的には、関数ポインタを使用してCでエミュレートされます。例えば、私は私がimage_scaler(画像を取り込み、新しい次元にそれをリサイズし、何かを)表すために使用される構造体を持っていた場合、私はこのような何かを行うことができます:

struct image_scaler { 
    //member variables 
    int (*scale)(int, int, int*); 
} 

その後、私はいくつかの画像スケーラを作ることができます以下のような:

struct image_scaler nn, bilinear; 
nn->scale = &nearest_neighbor_scale; 
bilinear->scale = &bilinear_scale; 

これは私がimage_scalerに取り、それは単にそれに異なるimage_scalerを渡すことによって、スケールの方法だ使用する任意の機能のための多型動作を実現することができます。

継承

継承は、通常のような達成される:

struct base{ 
    int x; 
    int y; 
} 

struct derived{ 
    struct base; 
    int z; 
} 

は今、私はベースのすべての「継承された」フィールドの取得に伴い、の派生余分なフィールドを使用して自由です。さらに、構造体ベースのみを取り入れる関数がある場合。構造体derviedポインタを構造体の基本ポインタにキャストするだけで済みます。

+0

ありがとうFalain(私はupvoted)。これを行うライブラリを指すことができますか?私や他の誰かが実装全体を調べることができますか? – SetJmp

0

Daleのアプローチと似ていますが、PostgreSQLが内部的に構文木ノードや式の型などを表現する方法があります。デフォルトNodeExpr構造体はNodeTagは、unsigned int型のtypedefである

typedef struct { 
    NodeTag n; 
} Node; 

の線に沿って、があり、そしてすべての可能なノードタイプを記述する定数の束とヘッダファイルがあります。ノード自体は次のようになります。

typedef struct { 
    NodeTag n = FOO_NODE; 
    /* other members go here */ 
} FooNode; 

FooNodeがあるため、Cの構造体の癖で、大手を振ってNodeにキャストすることができます:2つの構造体は、同一の第1のメンバーを持っている場合、彼らはお互いにキャストすることができます。

はい、これはFooNodeBarNodeにキャストすることができますが、これはおそらくやりたくないことを意味します。適切な実行時の型チェックが必要な場合は、GObjectを使用することができます。

(注:メモリは、例から、私はしばらくの間でのPostgresの内部にハッキングされていない developer FAQは、より多くの情報を持っています。)

+0

長い間ずっと前(1988年頃)私はCコンパイラを使っていましたが、パースノードは個々のノードタイプのビットユニオンであり、ユニオンのどの枝が有効であるかを決めるためにユニオンの外側にタイプタグがあります。あなたは説明します。今日、私はほぼ確実に上記の私の提案のラインに沿ってそれを行うでしょう。私は関数ポインタを使用すると、呼び出し側が呼び出す関数の名前を知らないので、目的のパブリックAPIを定義する必要があることがわかります。実装に関する内部データを使用するために関数を通過するのは非常に難しいです。 –

+0

Sigh ... s/bit union/big union /上記にあります。入力ミスを申し訳ありません。 –

+0

関数ポインタのアプローチは優れています.1つは、バインディングメソッドをオブジェクトに近似させることです。私はあなたの例が好きで、それを票決しました。 –

2

あなたはすべての答えを閲覧から見ることができるように、ライブラリがあり、 関数ポインタ、継承、カプセル化などの手段があります。すべて が利用可能です(C++はもともとCのフロントエンドでした)。

しかし、ソフトウェアにとって非常に重要な側面は、可読性が であることがわかりました。 10年前からコードを読もうとしましたか? その結果、私はC.

で オブジェクトのようなものをやったときに、最も単純なアプローチを取る傾向にある次のことを確認する:

  1. は期限を顧客のために、このです(もしそうなら、OOPを考えます) ?
  2. OOPを使用することはできますか(コードが少なくて済み、開発が速く、読みやすくなります)?
  3. ライブラリ(既存のコード、既存のテンプレート)を使用できますか?
  4. 私はメモリまたはCPU(たとえばArduino)に制約されていますか?
  5. Cを使用する別の技術的な理由はありますか?
  6. 私のCを非常にシンプルで読みやすく保つことができますか?
  7. 私のプロジェクトにはどんなOOP機能が本当に必要ですか?

私は通常、 に私のコードをカプセル化し、非常に読みやすいインターフェイスを提供することができますGLIB APIのようなものに戻ります。 がさらに必要な場合は、多型のための関数ポインタを追加します。

関連する問題