2009-06-07 36 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;  
} 

但是,這似乎只是單調乏味的,違反C.精神更何況,這是一種窮人的OO。

這個程序最終會變得相當大,所以從一個好的設計組織開始是至關重要的。我想象着在C開發多年的過程中,某些設計模式已經在如何最好地構建可維護性代碼方面發展。就像函數式編程一樣,我希望過程式編程有一個清晰可讀的範例。

指向相關文章和書籍也是可以接受的。

+0

我討厭只選擇一個答案,因爲它們都具有有用的花絮,但不透明指針引用可能是最有用的東西,我是不知道的。謝謝! – HVS 2009-06-07 13:04:35

回答

15

這是相當正常和明智的做法。但是儘量不要在頭文件中公開結構佈局,以便在實現它的方式和更好地管理依賴關係方面有一定的靈活性。

查看Opaque pointer瞭解更多詳情。

+1

讓我想起HWND,本地win32 C api – bobobobo 2009-06-07 14:21:59

11

你在暗示的是我一直寫C程序的方式,當時我做了這樣的事情。我不認爲這是「可憐的OO」,我認爲這是明智的程序編程實踐。

我會觀察幾件事情對你的C代碼:

  • 與結構定義,使用typedef,所以你並不需要分散在整個代碼中的「結構」關鍵字
  • 僅使用時投下他們實際上是需要 - 在返回值中投將通過malloc()是不必要的
+0

好的提示。 「窮人OO」的意思是它是一個非常有限的OO(即沒有多態性,沒有封裝等)。 – HVS 2009-06-07 12:22:29

+1

但是請注意,typedefs被認爲是一些不好的做法,包括Linux內核團隊 – temp2290 2009-10-23 21:24:50

1

C已是一個低層次的語言,並在尊重它會組織按照你的代碼的數據結構非常有用功能和模塊。

我建議您在任何想要創建數據對象的地方使用typedefs和枚舉。根據需要使用宏或靜態函數來初始化,分配和「銷燬」。

3

嗯...我們過去只是使用命名約定...... Ergo:str *用什麼常見的數據結構做什麼?所以也許只需要C#語法和s /./_/ g?

  • foo_constructor
  • foo_destructor
  • foo_someMethod
  • foo_someMethod2 //是不是在ANSI C
  • foo_otherMethod

沒有超載......並沒有沒有繼承。 ..

  • foo2_constructor
  • foo2_destructor
  • foo2_someMethod //並沒有任何多態性

但看看光明的一面...您可以使用指針到指針TO-指針到函數返回,一個指針到指針-INT!哦,快樂!

我最好的建議是學習Java的教訓(並通過推理C#),並將你的庫結構化爲無副作用...更多typdefs ==更少的頭痛......如果你的解決方法如何按照這個聖人提醒,請讓我知道;-)

乾杯。基思。

+0

通過「副作用」,我假設你的意思是有靜態變量,全局變量等?顯然,這些庫會對它們修改的「對象」產生副作用。 – HVS 2009-06-07 12:59:36

+0

通常,您可以返回新狀態,而不是爲了更新某個狀態而改變現有狀態,這與功能性編程一致,並且會使數據流依賴性更加明確且更容易遵循。 – none 2009-06-07 13:52:49

2

這是一個非常合理的方式來寫一個C​​程序。還有另外一個大型應用程序,它們的功能大致相同 - 稱爲Linux內核。使用的一些近OO的功能在裏面:

  • 結構和業務結構上進行封裝,就像在你的榜樣
  • 指針的基礎結構爲窮人的繼承形式 - 你會發現 負荷引用結構的kobject在那裏
  • 宏來生成用作模板編程
1

我上面的建議達成一致的替代品。你正在做的最好的方式。如果你想在C編程

當然,你可以寫一個預處理器自動生成這些聲明和你的東西..也許用「類」的聲明。 ..把你想成爲裏面的類成員函數的功能..等

但是我們這裏有一個簡單的C++到C編譯器。爲什麼不用C++編程,使用真正的C++編譯器,使用乾淨的接口,並將C++代碼與C代碼鏈接?無論如何,你需要在C和C++中編寫代碼的原因是什麼?或者,如果您需要,可以從編譯器生成C代碼,並將輸出的C代碼與您需要的任何其他代碼一起編譯。

+1

我真的不是C++的粉絲,雖然它在過去幾年裏有了很大的提升(Boost是一個偉大的庫)。 除此之外,這個項目的一部分是相當低級的,這是選擇C的原因之一。另一個是它將是開源的,並希望儘可能保持靈活性。我*可以用C++來完成,但是這會導致更多的問題,我覺得這是值得的。 – HVS 2009-06-07 21:12:15

+1

你不需要使用所有的功能 - 只要堅持一個非常簡單的子集 - 即類,方法,構造函數,析構函數 - 保留其餘的標準c。對於開源版本,您可以運行C++ to C編譯器並分發C代碼。 – 2009-06-08 15:48:40

+0

C是我們在低層次所做的,C++對Linux生態系統幾乎沒有任何價值。你要麼做得很對,用C慢慢用,或者用像golang這樣的現代語言來完成你還想完全編譯的東西。 C++是代碼開發人員,這與風格是對立的,Linus說得很對。 – TechZilla 2016-01-02 01:09:12

0

我已經在一點點的一個項目工作,而在庫需要在C,但我希望有某種形式的面向對象的功能。我正在做一些類似於此的更多細節。

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 2009-06-07 21:07:56

相關問題