2012-04-18 35 views
4

我有一個函數使用OpenGL繪製一個圓,我想傳遞一個包含x和y座標以及半徑的結構。問題是這個函數必須與3個不同的結構一起使用,所有結構都包含繪圖函數不使用的座標,半徑和其他一些東西。C:爲一個函數參數發送不同的結構

是否有某種方法只有一個參數爲3個不同的結構(一次只發送一個參數)。

我希望我已經足夠精確。 PS:函數必須是「抽象的」。

回答

3

是的,你可以使用一個原型是這樣的:

void foo(char type, void *data); 

使用類型確定要使用的數據作爲其結構的功能,你是好。

struct c *prepareStructC(void); 
//... 
struct c *toto = prepareStructC(); 
foo('c', toto); 
//... 
void foo(char type, void *data) 
{ 
    int x, y; 
    switch (type) 
    { 
    case 'c': 
     x = ((struct c*)data)->x; 
     y = ((struct c*)data)->y; 
     break; 
    //... 
    } 
    //... 
} 

第二種選擇,如果你想避免一個開關/箱,並能夠在事後添加更多的結構類型,沒有演變FOO,您可以確保所有的結構開始提供必要的數據,總是以相同的順序,相同的類型。這樣,您就可以像在C++的「接口」,並使用類型的抽象形式:

struct abstract 
{ 
    int x; 
    int y; 
    int radius; 
} 

struct a 
{ 
    struct abstract abs; 
    //... other data ... 
} 
struct b 
{ 
    struct abstract abs; 
    //... other data ... 
} 
struct c 
{ 
    struct abstract abs; 
    //... other data ... 
} 

//Two choices : either you have: 
void foo(void *data) 
{ 
    int x,y,r; 
    x = ((struct abstract*)data)->x; 
    y = ((struct abstract*)data)->y; 
    r = ((struct abstract*)data)->radius; 
    //... 
} 

//OR Smarter way: 
void foo2(struct abstract *data) 
{ 
    int x,y,r; 
    x = data->x; 
    y = data->y; 
    r = data->radius; 
} 
//Calling foo2 with: 
struct a *sa = prepareStructA(); 
struct b *sb = prepareStructB(); 
struct c *sc = prepareStructC(); 
foo2(sa->abs); 
foo2(sb->abs); 
foo2(sc->abs); 

第二種方法的第二部分可以讓你更多的靈活性,在亞型打破的具體信息,使你把abs部分放在struct a/b/c的任何地方,並且在結構單一目的的原則中更好(座標和半徑爲其他東西並不總是最好的。)

+0

+1用更聰明的方式第二個選項:這正是OO是如何在C. – mouviciel 2012-04-18 15:45:38

+0

謝謝你們實現,我在一個結構包含一個struct的打算。 – DennisVDB 2012-04-18 16:55:04

1

僅當函數接受void*作爲參數,然後您將void*投射到第在解引用它來訪問其中的數據之前,在函數中使用正確的指針類型。

typedef enum 
{ 
    type1, type2, type3 
} datatype; 

void foo(void* data, datatype type) 
{ 
    switch(type) 
    { 
     case type1: 
     // do something with data by casting it to the proper type 
     break; 

     // ... other cases here 
    } 
} 

然而,這樣做你會)需要通過另一種說法,表示正在鑄造到void*傳遞之前的原始類型,和b)你放棄的類型系統,這是幾乎沒有一個好主意並應始終避免。

如果採取這種方法,高度建議創建調用函數(即取void*)內部之前採取正確的三個類型分別爲「包裝」的功能。使其成爲嚴格的約定,從不直接調用void*函數;只調用包裝器。以這種方式,你仍然有類型系統來幫助編譯錯誤。

void bar1(someStruct* data) 
{ 
    foo((void*) data, type1); 
} 
void bar2(someOtherStruct* data) 
{ 
    foo((void*) data, type2); 
} 
void bar3(yetAnotherStruct* data) 
{ 
    foo((void*) data, type3); 
} 
+0

你是對的,枚舉比一個普通的「char」更好,我的第一個方法更加骯髒^^「 – Eregrith 2012-04-18 15:42:29

+0

同意,但是你用一個相同的數據」簽名「開始單獨的結構是很好的一點,類型系統和(理論上)隨着時間的推移對主要功能的更改較少。 – 2012-04-18 15:47:07