<a target="_blank" href="http://blog.csdn.net/chief1985/article/details/2008479">用C語言模拟面向對象程式設計(上)</a>
導讀:
用C語言模拟面向對象程式設計
雖然我接觸計算機已經有将近一年了,但一直以來我不願意寫技術方面的文檔,因為所謂的“技術”就是照着做得東西, 即使可能遇到一些難題,到網上搜尋一下就可以解決,不值得把網上長篇累牍的文檔複制粘貼到這裡來。即使是自己寫,也是寫些别人已經解決過的東西。是以不論是數學,還是計算機,在這裡我沒有寫過那種簡單搬運知識的文章。
但即使再純粹的技術,弄得時間長了都會産生一些獨特的想法和感受,記錄這些想法可能不光對自己是有意義的。今天來寫第一篇偏向技術的東西。
如何在C語言中用面向對象的思路寫程式?這已經是很多人考慮過的問題了,而且實際上已經有人在用C語言實作一些面向對象的項目了,比如,在Linux下大名鼎鼎的圖形界面GNOME,就是通過C語言模拟的面向對象特性來實作的。
在一本名叫《面向對象程式設計,C++和Java比較教程》的書中有一個抛磚引玉的例子,代碼如下(見該書中文版第67頁,其中注釋塊中是自己的評注):
/* SimulatedOO.c */
#include
/* 基類型: */
typedef struct
{
char * name;
int age;
} User;
/* 子類型: */
User genericUser;
char ** listOfCourses;
int numCourses;
int whatYear;
} StudentUser;
/*********************************************************
* 這樣, 在子類型 StudentUser 中就有一個基類 User 的結構體
* 變量, 并且在記憶體中 User 結構體占據 StudentUser 的開頭部分,
* 這樣,把一個指向 StudentUser 類型的指針強制類型轉換到 User*
* 類型,就可以通路到 User 的相應區域,這樣就實作了繼承機制。
********************************************************/
/* 為基類型User定義的函數: */
void setUserName( User* user,char aName[] ) {
user -> name = malloc(strlen(aName)+1); /* 原文為 malloc( sizeof(strlen(aName)+1) ), 這是不正确的。*/
strcpy(user->name,aName);
}
char * getUserName( User * user) {
printf("/nName of user: %s/n",user->name);
return user->name;
void setUserAge(User * user,int yy) {
user -> age=yy;
int getUserAge( User * user ) {
printf("%s's age: %d/n",user->name,user->age);
return user-> age;
/* 為基類型User定義的函數: */
/**************************************************
* 這個函數在書中是用來展示多态行為的,不過這種實作多态的
* 方式并不是很好,并不能實作類似于C++或Java中多态的動态連
* 接機制。具體用法見主程式中注釋為“多态行為” 那兩行。
*************************************************/
int isSenior( User * user ) {
if ( user->age >70 ) return 1;
else return 0;
/* 為子類型 StudentUser 定義的函數: */
void setListOfCourses( StudentUser* student,char* listCrs[],int nCourses) {
int i;
char ** temp;
student->numCourses = nCourses;
temp = malloc( nCourses * sizeof( char* ));
student->listOfCourses=temp;
for(i=0;i numCourses;i++) {
*temp = malloc( strlen( *listCrs )+1);
strcpy(*temp,*listCrs);
*temp++;
listCrs++;
void printListOfCourses( StudentUser * student ) {
temp = student->listOfCourses;
printf("/n%s's courses: /n",student->genericUser.name);
for(i=0;i numCourses;i++)
printf("%s/n",*(temp++));
void setYear( StudentUser* student,int yy) {
student->whatYear=yy;
int getYear( StudentUser* student) {
return student->whatYear;
int main()
User * zaphod;
StudentUser* trillian;
char * listCourses[]={"Physics","Chemistry","algebra"};
int numCrs = sizeof(listCourses)/sizeof(listCourses[0]);
zaphod = malloc(sizeof(User));
setUserName(zaphod,"Zaphod");
setUserAge(zaphod,89);
getUserName(zaphod);
getUserAge(zaphod);
trillian=malloc(sizeof(StudentUser));
setUserName((User*)trillian,"Trillian" );
setUserAge((User*)trillian,18);
getUserName((User*)trillian);
getUserAge((User*)trillian);
setListOfCourses(trillian,listCourses,numCrs);
printListOfCourses(trillian);
/* 多态行為 */
printf("/nZaphod is senior is %s/n",isSenior(zaphod)? "true":"false");
printf("/nTrillian is senior is %s/n", isSenior((User*)trillian)? "true":"false");
/*****************************************************
* 和setUserAge 、setUserName之類的函數一樣,isSenior
* 需要一個基類指針參數,通過将 trillian 轉換為 User*
* 類型,就會把指向trillian 中User域的指針傳進函數。
* ***************************************************/
printf("name field of trillian is at address: %p/n", &( trillian->genericUser.name ));
printf("trillian when cast to User* is at address: %p/n",(User*)trillian );
/***************************************************
* 這兩行輸出的位址值是一樣的。
* *************************************************/
在C++和Java中,多态行為是由一種動态連接配接機實作的,比如,在C++中定義如下的類 Base 和它的子類 Sub:
class Base {
int data;
public:
Base() : data(3) {}
virtual int getData() const {
return data;
};
class Sub:public Base {
Sub() : data(5) {}
int getData() const {
那麼如果有一個Base 類型的指針指向了一個Sub類,通過這個指針調用getData()時将傳回子類Sub中的data:初始值5。這樣,如果有一個儲存基類型指針的數組,但這些指針有的指向基類,有的指向子類,那麼我就可以通過指針統一地調用 getData() 函數,依然能夠得到正确的值。
怎麼在C中也實作類似的功能呢? (待續)
本文轉自
http://blog.csdn.net/chief1985/article/details/2008479
<a target="_blank" href="http://blog.blogwhy.com/tpfly/e_23482.html">http://blog.blogwhy.com/tpfly/e_23482.html</a>