C 語言實現 C++ 多態


C 還是 C++?

C++ 中的多態是指「通過基類對象的指針或者基類對象的引用調用虛函數」,表現更多派生類的特性,但根據 C++ 多態的實現,我們發現這種方法存在一定的空間和效率的折損。不可否認,多態輕松解決了很多工程中遇到的問題,這與 pure C 的解決方法比起來,更為優雅。

在考慮移植性上,C 的光芒要蓋過 C++,但 C++ 的多態是可借鑒的,於是用 pure C 來模仿 C++ 中多態行為。

C 如何實現多態

在 C 中沒有類的概念,但有 struct,而且 C 中的 struct 是不允許有函數的,只允許存在變量,那是不是函數變量就允許存在了?!所以,函數指針可以給我們一些提示。

假定有一個結構體 struct Animal 聲明如下:

struct Animal
{
     void (*move)();
};

此時 Animal 中的 move 只是一個指針,並沒有賦值,也就是說它不能代表任何的行為,但我們可以在 main 函數中對其進行賦值,賦予相應的行為。

void Animal_move()
{
     printf("Animal move.\n");
}

再假定一個結構體 struct Rabbit,我們可以暫且把它看作(因為 C 中沒有繼承概念)struct Animal 的派生類,聲明如下:

struct Rabbit
{
     void (*move)();
};

同樣我們可以給 Rabbit 的 move 預定義一個行為:

void Rabbit_move()
{
     printf("Rabbit move.\n");
}

struct Animal 和 struct Rabbit 在內容上完全一致,而且變量對齊上也完全一致,可以通過將 struct Rabbit 類型的指針強制轉換為 struct Animal 類型的指針,即:

     Animal *panimal;
     Rabbit rabbit;

     //...

     panimal = (Animal*)&rabbit;

這樣,我們就可以通過 struct Animal 類型的指針或者引用來操縱 struct Rabbit 類型的對象了。

int main(void)
{
     Animal *panimal;

     Rabbit rabbit;

     rabbit.move=Rabbit_move;

     panimal = (Animal*)&rabbit;

     panimal->move();
}

Rabbit move.
請按任意鍵繼續. . .

C 多態有什么問題

是不是有需要注意的問題?為什么剛才特別提出「在內容上完全一致,而且變量對齊上也完全一致」?倘若把 struct Animal 的聲明作稍微的改變:

struct Animal
{
     int age;
     void (*move)();
};

運行崩潰了,並不能得到上面的執行結果,原因是 move 函數指針 在struct Animal 中和 struct Rabbit 中的偏移量不同,結構體是根據變量在結構體的偏移量來讀取或者修改變量的。當執行 panimal->move(); 的時候,實際上引用了非法的地址:

panimal->move();

可以被形象的轉化為:

( * (panimal+sizeof(age)) ) ();

但發現 panimal 是指向 struct Rabbit 實體的,panimal+sizeof(age) 已經指向了非法地址:

struct Rabbit 結構 調用
void (*move )(); <------ rabbit.move();
非法地址 <------ panimal->move();

因此需要模擬多態,必須保持函數指針變量對齊

在一些 c 開源項目中經常用到這種設計,譬如 libevent。

搗亂 2013-05-09

http://daoluan.net


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM