2010-07-23 71 views
5

一個破解多態性在C限量表的辦法是做這樣的事情:C中的半繼承:這段代碼如何工作?

typedef struct { 
    int x; 
} base; 

typedef struct { 
    base super; 
    int y; 
} derived; 

現在,您可以參考派生實例作爲基本實例,這取決於變量是怎麼投,即:

derived my_derived; 
my_derived.y = 10; 
my_derived.super.x = 20; 
//will print 10 
printf("%d", (&my_derived)->y); 
//will print 20 
printf("%d", ((base*)(&my_derived))->x); 

所以我的問題是,這是如何工作的?是因爲當你把它作爲基礎並引用一個變量時,你引用int成員'x'作爲'base'結構開頭的偏移量?這是我能想到的唯一的事情,任何幫助將不勝感激。

非常感謝!

回答

11

在一個結構體中,可以在數據元素之間或結構體的末尾有未命名的填充字節,但不在開始處。因此,struct-type對象的第一個數據元素的地址保證與struct-type對象本身的地址相同。

因此,在您的示例中,my_derived的地址與my_derived.super的地址相同。

+2

+1這實際上是由C規格保證。 – bta 2010-07-23 21:56:11

1

是因爲當你把它作爲基礎並引用一個變量時,你引用int成員'x'作爲'base'結構開始的偏移量?

是。這種技術有時被稱爲「類型雙關」。

這是用在POSIX標準庫中;例如,在struct sockaddr中。通常你將它聲明爲sockaddr_storage,將其作爲sockaddr傳遞,並根據sockaddr_in或_in6將其作爲sockaddr_in或_in6進行處理,具體取決於其中實際存儲的地址類型。

2

結構是一個字節區內存,編譯器知道他的結構,也就是你在裏面聲明瞭哪些變量。

例如,你可以聲明一個結構:

struct st { 
    int number; 
}; 

struct st n; 
n.number = 10; 
printf("n=%i\n", n.number); 

但你可以改變編譯器的行爲,例如聲明字符指針在你的結構:

char *c = (char*)&n; 
printf("char c=%c\n", c[0]); 

這是一個法律聲明。然後,您可以隨時更改該內存區域的結構。唯一重要的是你的聲明結構的內存地址。

在您的例子中,當聲明的派生結構節目保存的存儲器區域分配派生stucture,但形式,編譯器看到這個區域可以被改變的任何時間:

struct derived my_derived; 
struct base *b = (struct base*)&my_derived; 

b->x = 20; 
my_derived.y = 10; 
printf("x=%i y=%i\n", my_derived.base.x, my_derived.y); 

在這種情況下b和& my_derived共享相同的內存區域,你只能改變編譯器如何「看見」這個區域。

「type punning」的使用是C語言中的oop遺產模擬的基礎,這是一種非oop編程語言。

我用在我的項目這種技術:oop4c