2009-06-07 15 views
27

まず、CとC++の両方でかなりの量の経験があるとしましょう。しかし、私はCで新しいプロジェクトを開始しています。オブジェクト指向言語で長い間(C#とC++)作業してきましたが、手続き型言語で機能をカプセル化する効果的な方法を考え出すのに問題があります。私が最初に考えたのは、単に私のOOの知識や構造、それを上の背中のような何か落ちた:Cプログラムを効果的に構築する方法

struct Foo 
{ 
    int x; 
    char *y; 
}; 

struct Foo *new_Foo() 
{ 
    return (struct Foo *)malloc(sizeof(struct Foo)); 
} 

void Foo_member_function(struct Foo *foo, int z) 
{ 
    foo->x = z;  
} 

をしかし、それはちょうどそれが貧しい人のOOであることは言うまでもありませんC.の精神に退屈とは逆らしいです。

このプログラムは最終的にはかなり大きなものになるので、良い設計組織から出発することが重要です。私はC言語で長年の開発をしていると思いますが、保守性のためにコードを最適に構築するための設計パターンがいくつか開発されています。関数型プログラミングと同様に、私は、手続き型プログラミングにはクリーンで公正なパラダイムが望まれます。

関連記事や書籍へのポインタも同様です。

+0

すべてが役に立つチープビットを持っているので、1つの答えを選ぶのは嫌ですが、不透明ポインタの参照はおそらく私が気づいていない最も有用なものでした。ありがとう! – HVS

答えて

15

これは非常に正常かつ賢明な方法です。しかし、ヘッダーファイルに構造体レイアウトを公開しないようにしてください。そうすれば、実装方法や依存関係をより柔軟に管理できます。

詳細はOpaque pointerを参照してください。

+1

はHWNDとネイティブwin32 C APIを思い出させます – bobobobo

11

あなたが示唆しているのは、私がそのようなことをした日に私がいつもCプログラムを書いた方法です。私はそれが "貧乏人"とは思わない、私はそれが合理的な手続きプログラミングの練習だと思う。

私はあなたのCコードに関する物事のカップルを観察します:あなたは

  • のみ使用がときキャストコード全体で「構造体」キーワードを散乱する必要はありませんので、構造体の定義と

    • 使用のtypedefをそれらは実際に必要です - malloc()からの戻り値のキャストは不要です
  • +0

    良いヒント。私が「貧乏人OO」と言ったのは、それが非常に限定されたOO(すなわち、多形性なし、カプセル化なしなど)であったということでした。 – HVS

    +1

    しかし、typedefは、Linux kernal crewを含む一部の人にとっては悪い習慣とみなされていることに注意してください。 – temp2290

    1

    Cは低レベルの言語であり、あなたのコードに従ってデータ構造を整理することは非常に便利です機能とモジュール。

    データオブジェクトを作成する場合はいつでも、typedefと列挙を使用することをお勧めします。マクロや静的関数を使用して、必要に応じて初期化、割り当て、破棄を行います。

    3

    Hmmm ...私たちは命名規則を使用するだけでした... Ergo:str *は何の共通データ構造を持っていますか?だから多分C#の構文とs /./_/gを取るだけでしょうか?

    • foo_constructor
    • foo_destructor
    • foo_someMethod
    • foo_someMethod2 //はANSI Cにはオーバーロード
    • foo_otherMethod

    ません...と何の継承はありません。 ..

    • foo2_constructor
    • foo2_destructor
    • foo2_someMethod //と何の多型

    しかし、明るい面に見えるはありません...あなたは、ポインタへのポインタ対を使用することができますポインタから関数へ戻るポインタからポインタへのポインタ!ああ、喜び!

    私の最善のアドバイスは、Java(そして推論C#)の教訓を学び、ライブラリに副作用がないように構造化することです... more typdefs ==頭痛の軽減...そしてあなたのワークアウトの方法このセイジに従ってください助けてください私に教えてください;-)

    乾杯。キース。

    +0

    "副作用"とは、静的変数、明らかに、ライブラリは変更する「オブジェクト」に副作用があります。 – HVS

    +0

    一般的に、ある状態を更新するために既存の状態を変更するのではなく、新しい状態を返すことができます。これは関数型プログラミングと一致しており、データフローの依存関係をはるかに明示しやすくします。 – none

    2

    これは、Cプログラムを書くのにかなり合理的な方法です。そこにはLinuxカーネルと呼ばれる別の大きなアプリケーションがあります。そこで使用されるいくつかのほぼOO-機能:貧乏人の継承の形としてちょうどあなたの例のようにカプセル化のための構造体に

    • 構造体やオペレーションベースの構造体へ
    • ポインタ - あなたは の負荷を見つけることができます私は上記の提案に同意したテンプレートプログラミング
    1

    の代替としての機能を生成することが

  • マクロでたkobject構造体への参照。もしあなたがC言語でプログラムしたいのであれば、最良の方法です。

    もちろん、これらの宣言やものを自動的に生成するプリプロセッサを書くこともできます。 "Class"宣言を使うこともできます。 ..あなたがメンバー関数にしたい関数をクラスの中に入れなさい。

    しかしここでは、C++からCへの単純なコンパイラを紹介します。単にC++でプログラミングするだけでなく、実際のC++コンパイラを使用し、クリーンなインターフェイスを使用し、C++コードをCコードとリンクさせるのはなぜですか?とにかくCとC++でコーディングする必要がある理由は何ですか?または、必要な場合は、コンパイラからCコードを生成し、必要なものと一緒に出力Cコードをコンパイルします。

  • +1

    私は本当にC++のファンではありません。過去数年間で大きく向上しましたが(Boostは素晴らしいライブラリです)。 これ以外にも、このプロジェクトの一部はかなり低レベルです。これはCを選択した理由の1つです。もう1つはオープンソースであり、可能な限り柔軟に保つことです。私はC++で行うことができますが、それはそれが価値があると感じる多くの問題を引き起こすでしょう。 – HVS

    +1

    すべての機能を使用する必要はありません。クラス、メソッド、コンストラクタ、デストラクタなどの非常に単純なサブセットに固執するだけで、残りの部分を標準の状態に保ちます。オープンソースのリリースでは、C++コンパイラを実行してCコードを配布することができます。 –

    +0

    Cは、私たちが下位レベルでやっていることですが、C++はLinuxエコシステムにとってほとんど価値がありません。あなたはそれを正しく行うか、Cで本当に遅くするか、あるいは完全にコンパイルしたいものにはgolangのような現代的な言語を使用します。 C++はコードの開発者であり、それはその精神に反するものです。 – TechZilla

    0

    私は、ライブラリをC言語にする必要があるのに少しだけプロジェクトに取り組んでいますが、いくつかのOO機能を使いたいと思っています。私はもう少し詳しくこれに似た何かをやっています。

    struct klass { 
        char * value; 
    
        void (*set_value) (struct klass *, const char *); 
        void (*destroy) (struct klass *); 
    }; 
    
    static void 
    klass_method_set_value (struct klass * k, const char * value) { 
        if (k->value == NULL) { 
        } 
    } 
    
    static void 
    klass_object_desetroy (struct klass * k) { 
        free (k); 
        k = NULL; 
    } 
    
    static void 
    klass_method_destroy (struct klass * k) { 
        klass_object_destroy (k); 
    } 
    
    static struct klass * 
    klass_object_init (void) { 
        struct klass * obj = (struct klass *) malloc (sizeof (struct klass*)); 
    
        /* members */ 
        obj->value = NULL; 
    
        /* methods */ 
        obj->set_value = klass_method_set_value; 
        obj->destroy = klass_method_destroy; 
        return obj; 
    } 
    
    struct klass * 
    klass_new (void) { 
        return klass_object_init(); 
    } 
    

    何かが間違っている場合は私を許してください。少し速くそれを書いた。

    +0

    ええ、それは私が避けたかったものです。私はそれが基本的にStroustrupが最初のC++コンパイラをコード化したものだと聞いてきました。 – HVS

    関連する問題