免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 19969 | 回复: 63
打印 上一主题 下一主题

[C] [转载]OO Programing in C [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-24 09:54 |只看该作者 |倒序浏览
最近看c版很多人讨论c的面向对象,前天突然在别的论坛看到这个帖子,又因为今天早上醒得早,就copy过来了
http://www.javaeye.com/topic/150575
http://www.javaeye.com/topic/150578
http://www.javaeye.com/topic/150581
作者:rubynroll
----------------------------------------------------------------------------------------------------------------
经常看到关于OO编程的讨论,C++, Java, C#...还有最近很流行的动态语言Python,Ruby等,但很少看到有C的份。


在我看来,OO编程的核心是OO的思想,用什么语言倒是其次。但是,不可否认,那些专门为OO编程设计的语言可以比较方便和自然地表达OO思想,有些语言甚至强制使用OO特性。


C,作为最贴近底层的高级语言,拥有简洁的语法和直接内存操作能力(指针),大量运用于系统级编程,如操作系统内核,驱动程序等。而在嵌入式系统中,由于资源有限等因素,更倾向于用C编程。

C虽然在语言特性上并没有体现OO特性,但是依然可以通过各种编程技巧来体现OO的思想。由于C的高度自由的特点,在OO编程方面还能体现有别于其他语言的特殊韵味。


OO思想在Unix世界中很早就有:UNIX把设备抽象成文件,这样就可以用一套相同的方法(open, read, write, close, ... )去访问不同的设备和文件——尽管设备之间的差异很大。用OO的观点来看,这些“设备”对象都实现了"文件操作接口",可以想象有一个叫"文件"的基类,定义了"文件操作接口",“设备”对象继承了“文件”对象....。在实现角度看,在内核里面,设备驱动提供了自己的read, write等实现,并用它们去填充文件操作结构体里面的函数指针....这和C++里面的虚函数运行时绑定的道理是一样的。( C++虚函数是其实是运行时静态绑定,而文件操作接口可以运行时动态绑定

Linux内核中则处处体现了OO的思想。2.6内核的Device Driver Modal是一套层次分明又错综复杂的机制,其中体现了许多OO设计理念。虽然可能设备驱动程序开发者觉察不到,但所有的设备驱动对象内部都隐藏了一个叫KObject的对象。内核把这些KObjects互相联系在一起,并通过KObject的相互关系构造了/sys文件系统。/sys就是内核中各种设备对象的映射图,如果把/sys全部展开,我们可以清楚地看到各种对象的关系。

实践证明,C也可以很好地用于OO编程,而且可以用于构造很复杂的系统,而且C在表达OO思想的时候并不会显得蹩脚,而是可以很简单,很自然。

[ 本帖最后由 gawk 于 2008-8-24 10:02 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2008-08-24 09:55 |只看该作者
“class“是很多OO编程语言里的关键字,它来源于OO鼻祖Smalltalk。class(类),是对一群有相同特性的对象的抽象概括,对象称为类的实例。在class里面可以存放有状态(变量),行为(函数/方法)....有关OO概念、方法的文章太多了,不再啰嗦。在C里面,唯一可以实现自定义类型的是struct,struct是C的OO编程最重要的工具。


一个最常见的技巧,就是用struct来"仿真"class: 在struct里面放入变量,函数指针,嵌入其他struct等。

以下例子摘自我最近刚开发完成的一个USB Firmware项目:


  1. struct usb_device;   
  2. struct usb_ctl;   
  3.   
  4. struct usb_iobuf {   
  5.   int len;              /* data length in the buffer */  
  6.     unsigned char buf[USBEPFIFO_SIZE];  /* data buffer itself */  
  7. };   
  8.   
  9. struct usb_endpoint {   int type;       /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */  
  10.     int qlen;       /* queue length */  
  11.   
  12.     xQueueHandle lock;  /* semaphore lock */  
  13.     xQueueHandle q;     /* data queue (pointer of bulk_buf) */  
  14.   
  15.     int idx;        /* endpoint index */  
  16.     int epx;        /* endpoint mark bit */  
  17.     int cfg;        /* endpoint configure */  
  18.     int bank;       /* current operation bank (for ping-pong mode) */  
  19.     int txCount;        /* used for ping-pong mode */   /* endpoint data process function */        void (*ep_process) (struct usb_device *dev,          struct usb_endpoint *ep,            xISRStatus *pxMessage);   
  20. };   
  21.   
  22. struct usb_descriptor {   
  23.     int type;       /* descriptor type: device, conf, string or endpoint */  
  24.     int idx;        /* descriptor index (for string descriptor) */  
  25.     int size;       /* descriptor size */  
  26.     void * data;        /* descriptor data */  
  27.     struct list_head list;  /* link list of descriptors */  
  28. };   
  29.   
  30. struct usb_deviceOps {   
  31.     int (*init)(struct usb_device *dev);        /* called when framework init usb device, add device descriptors, init private data ... etc. */  
  32.     int (*reset)(struct usb_device *dev);       /* called when reseted by host */  
  33.     int (*switch_in)(struct usb_device *dev);   /* called when switch in */  
  34.     int (*switch_out)(struct usb_device *dev);  /* called when swithc out */    /* called when HOST request class interface data */  
  35.     void (*class_interface_req)(struct usb_device *dev, xUSB_REQUEST *pxRequest);   /* called when HOST complete the data sending stage */      int (*ctl_data_comp)(struct usb_device *dev,                     xCONTROL_MESSAGE *pxMessage);   
  36. };   
  37.   
  38. struct usb_ctlOps {   
  39.     void (*ctl_transmit_null)(struct usb_ctl *ctl);   
  40.     void (*ctl_send_stall)(struct usb_ctl *ctl);   
  41.     void (*ctl_reset_ep0)(struct usb_ctl *ctl);   
  42.     void (*ctl_detach_usb)(struct usb_ctl *ctl);   
  43.     void (*ctl_attach_usb)(struct usb_ctl *ctl);   
  44.     void (*ctl_send_data)(struct usb_ctl *ctl, unsigned char *data,   
  45.             int req_len,   
  46.             int send_len,   
  47.             int is_des);   
  48. };   
  49.   
  50.   
  51. struct usb_ctl {   
  52.     int addr;           /* address alloced by host */  
  53.     int conf;           /* configuration set by host */  
  54.     eDRIVER_STATE state;        /* current status */  
  55.     xCONTROL_MESSAGE tx;        /* control transmit message */  
  56.     xCONTROL_MESSAGE rx;        /* control receive message */  
  57.     struct ubufm *bufmn;        /* 'usb_iobuf' buffer manager, shared by all usb devices */  
  58.     int prio;           /* the main task priority */  
  59.     xTaskHandle task_handle;    /* the main task handler */  
  60.     struct usb_ctlOps *ctlOps;  /* control endpoint operations */  
  61. };   
  62.   
  63. struct usb_device {   
  64.     char name[16];          /* device name, e.g. "usbser" */  
  65.     struct usb_deviceOps *ops;  /* usb device callback functions */  
  66.   
  67.     struct usb_ctl *ctl;        /* usb control enpoint, provided by framework */  
  68.     struct list_head desc_list; /* usb descriptors */  
  69.     struct usb_endpoint *ep[MAX_ENDPOINTS]; /* endpoints */  
  70.     int active;         /* whether the device is active */  
  71.     xQueueHandle ready;     /* notify this queue when usb device ready */  
  72.     void *private;          /* device private data */  
  73.     struct list_head list;      /* link list of usb device */  
  74. };  

  75. struct usb_device;
  76. struct usb_ctl;

  77. struct usb_iobuf {
  78.   int len;                                /* data length in the buffer */
  79.         unsigned char buf[USBEPFIFO_SIZE];        /* data buffer itself */
  80. };

  81. struct usb_endpoint {        int type;                /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
  82.         int qlen;                /* queue length */

  83.         xQueueHandle lock;        /* semaphore lock */
  84.         xQueueHandle q;                /* data queue (pointer of bulk_buf) */

  85.         int idx;                /* endpoint index */
  86.         int epx;                /* endpoint mark bit */
  87.         int cfg;                /* endpoint configure */
  88.         int bank;                /* current operation bank (for ping-pong mode) */
  89.         int txCount;                /* used for ping-pong mode */        /* endpoint data process function */                void (*ep_process) (struct usb_device *dev,                         struct usb_endpoint *ep,                         xISRStatus *pxMessage);
  90. };

  91. struct usb_descriptor {
  92.         int type;                /* descriptor type: device, conf, string or endpoint */
  93.         int idx;                /* descriptor index (for string descriptor) */
  94.         int size;                /* descriptor size */
  95.         void * data;                /* descriptor data */
  96.         struct list_head list;        /* link list of descriptors */
  97. };

  98. struct usb_deviceOps {
  99.         int (*init)(struct usb_device *dev);                /* called when framework init usb device, add device descriptors, init private data ... etc. */
  100.         int (*reset)(struct usb_device *dev);                /* called when reseted by host */
  101.         int (*switch_in)(struct usb_device *dev);        /* called when switch in */
  102.         int (*switch_out)(struct usb_device *dev);        /* called when swithc out */        /* called when HOST request class interface data */
  103.         void (*class_interface_req)(struct usb_device *dev, xUSB_REQUEST *pxRequest);        /* called when HOST complete the data sending stage */                int (*ctl_data_comp)(struct usb_device *dev,                                         xCONTROL_MESSAGE *pxMessage);
  104. };

  105. struct usb_ctlOps {
  106.         void (*ctl_transmit_null)(struct usb_ctl *ctl);
  107.         void (*ctl_send_stall)(struct usb_ctl *ctl);
  108.         void (*ctl_reset_ep0)(struct usb_ctl *ctl);
  109.         void (*ctl_detach_usb)(struct usb_ctl *ctl);
  110.         void (*ctl_attach_usb)(struct usb_ctl *ctl);
  111.         void (*ctl_send_data)(struct usb_ctl *ctl, unsigned char *data,
  112.                         int req_len,
  113.                         int send_len,
  114.                         int is_des);
  115. };


  116. struct usb_ctl {
  117.         int addr;                        /* address alloced by host */
  118.         int conf;                        /* configuration set by host */
  119.         eDRIVER_STATE state;                /* current status */
  120.         xCONTROL_MESSAGE tx;                /* control transmit message */
  121.         xCONTROL_MESSAGE rx;                /* control receive message */
  122.         struct ubufm *bufmn;                /* 'usb_iobuf' buffer manager, shared by all usb devices */
  123.         int prio;                        /* the main task priority */
  124.         xTaskHandle task_handle;        /* the main task handler */
  125.         struct usb_ctlOps *ctlOps;        /* control endpoint operations */
  126. };

  127. struct usb_device {
  128.         char name[16];                        /* device name, e.g. "usbser" */
  129.         struct usb_deviceOps *ops;        /* usb device callback functions */

  130.         struct usb_ctl *ctl;                /* usb control enpoint, provided by framework */
  131.         struct list_head desc_list;        /* usb descriptors */
  132.         struct usb_endpoint *ep[MAX_ENDPOINTS];        /* endpoints */
  133.         int active;                        /* whether the device is active */
  134.         xQueueHandle ready;                /* notify this queue when usb device ready */
  135.         void *private;                        /* device private data */
  136.         struct list_head list;                /* link list of usb device */
  137. };
复制代码

在这个例子,我用struct分别描述了USB设备,USB控制通道,USB端点,USB描述符和USB缓冲区对象。USB设备对象包含了若干个USB端点,一个USB控制通道指针,一个USB描述符表的表头(指向若干个USB描述符),和一个USB缓冲区管理对象。而且,USB设备对象还包含了name属性,一个由USB Framework调用的回调函数集,还有一个用于连接其他USB设备的链表节点。

值得一提的是,USB设备对象中有一个void *private 成员,可以指向任何数据。实际上在我的程序里,我实现了usb-serial和usb-mass-storage两个USB设备,对于usb-serial对象,private我弃之不用,而在usb-mass-storage对象中,private指向一个Mass storage对象,usb-mass-storage正是通过这个Mass storage对象访问外部大容量存储的(在我的程序里,Mass storage对象和一个MMC Card对象绑定,外部存储是SD/MMC卡)。由于对于每一种设备的具体实现来说,它知道private指向的是何种类型的设备,因此不会引起混乱。而外部程序根据需要在初始化USB设备对象前赋予private有意义的值——运行时动态绑定。

这一系列struct基本上如实地反映了USB DEVICE硬件逻辑和规范要求: "一个USB设备包含若干个端点,其中有一个固定的控制端点(端点0)。在枚举阶段USB设备要根据HOST的请求应答相应的描述符..."

现在回到OO的话题,这个例子中体现了"组合类":USB设备对象包含了USB端点对象,USB描述符对象...。还有动态绑定 (private成员)。从严格的OO意义上来看,好像有点"怪",不过我认为这恰恰是C的特点——简洁,直接。不信你用C++表达试试?也许会更漂亮,很OO,但是不一定会如此清爽!

P.S. : 熟悉USB Firmware开发的人可能对struct usb_endpoint中的epx,cfg,bank和txCount四个成员有异议,因为这些成员是和特定的硬件相关,并不是所有的USB硬件都支持ping-pong mode,所以bank和txCount不一定用得上,epx, cfg也可能因硬件的不同而不同。没错!更理想的设计是把与硬件相关的部分分离出来,用void *private指向各自的与硬件相关的配置——就像struct usb_device所采用方法,所以更好的版本应该是:


  1. struct usb_endpoint {   
  2.   int type;     /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */  
  3.   int qlen;     /* queue length */  
  4.   xQueueHandle lock;    /* semaphore lock */  
  5.   xQueueHandle q;   /* data queue (pointer of bulk_buf) */  
  6.   int idx;      /* endpoint index */  
  7.      
  8.   /* endpoint data process function */  
  9.   void (*ep_process)(struct usb_device *dev,    struct usb_endpoint *ep, xISRStatus *pxMessage);   
  10.   void *private;    /* endpoint private data (hardware relevant) */  
  11. };  

  12. struct usb_endpoint {
  13.   int type;                /* endpoint type: BULKIN, BULKOUT, CTL, ISO ... */
  14.   int qlen;                /* queue length */
  15.   xQueueHandle lock;        /* semaphore lock */
  16.   xQueueHandle q;        /* data queue (pointer of bulk_buf) */
  17.   int idx;                /* endpoint index */
  18.   
  19.   /* endpoint data process function */
  20.   void (*ep_process)(struct usb_device *dev,        struct usb_endpoint *ep, xISRStatus *pxMessage);
  21.   void *private;        /* endpoint private data (hardware relevant) */
  22. };
复制代码

tips: 用C表达的一个关键处就是要很好地应用struct来描述模型。

[ 本帖最后由 gawk 于 2008-8-24 09:58 编辑 ]

论坛徽章:
0
3 [报告]
发表于 2008-08-24 09:56 |只看该作者
OO的一个亮点是类的"继承",通过"继承",可以重用许多代码。而且"继承"也是现实生活中非常自然的一种关系。但是很不幸,C没有class,更没有提供"继承"的表达方式。既然能用C的struct来仿真class, 那能不能继续来仿真"继承"呢?答案是:possible。就像<<Inside the C++ Object Modal>>书中所叙述的那样——你可以用C来达到所有C++能做到的事。但这种仿真显然毫无实际应用价值。

"继承"是一种表达方式,代码重用才是目的。

为了重用代码,C++可以用"继承"的方式来巧妙的达到目的,但是也必须付出代价:你必须非常仔细地设计你的类族谱,要有前瞻性,要有可扩展性,要决定分多少个层次....这些都不是容易做到的事。

C别无选择,模块化设计,函数,宏....只能通过巧妙的设计才能达到代码可重用的目的。还是举个例子来说明C是如何做到"殊途同归"的吧。

"链表"是一个非常常用的数据结构,常用于管理无序的数据(对象)集合。链表操作,特别是双向链表操作很容易出错。重用一套通用操作链表的代码可以为我们省不少事。在C++中,我们可以用经典的STL中的list类。为了适应各种数据类型,list类用模板来实现。list类实现的很巧妙,功能很强,但是,不得不说,很少人用。其实不仅list类很少用,STL都很少人用。(希望这是我的一家之言,反正我所熟悉的C++程序员都不怎么用STL :-)当然在C++中你还有另外一个选择:实现一个List基类完成链表操作,要放入链表的类从List类继承而来,就拥有了一套操作list的方法。

Linux内核中用C提供了一套非常巧妙的方法操作链表,位于.../linux/include/linux/list.h,只用一些宏和inline函数来实现双向链表。摘抄一部分出来:


  1. ....   
  2. struct list_head {   
  3.     struct list_head *next, *prev;   
  4. };   
  5.   
  6.   
  7. #define LIST_HEAD_INIT(name) { &(name), &(name) }   
  8.   
  9. #define LIST_HEAD(name) \   
  10.     struct list_head name = LIST_HEAD_INIT(name)   
  11.   
  12. #define INIT_LIST_HEAD(ptr) do { \   
  13.     (ptr)->next = (ptr); (ptr)->prev = (ptr); \   
  14. } while (0)   
  15.   
  16. /*  
  17. * Insert a new entry between two known consecutive entries.  
  18. *  
  19. * This is only for internal list manipulation where we know  
  20. * the prev/next entries already!  
  21. */  
  22. static inline void __list_add(struct list_head *new,   
  23.                   struct list_head *prev,   
  24.                   struct list_head *next)   
  25. {   
  26.     next->prev = new;   
  27.     new->next = next;   
  28.     new->prev = prev;   
  29.     prev->next = new;   
  30. }   
  31.   
  32. /**  
  33. * list_add - add a new entry  
  34. * @new: new entry to be added  
  35. * @head: list head to add it after  
  36. *  
  37. * Insert a new entry after the specified head.  
  38. * This is good for implementing stacks.  
  39. */  
  40. static inline void list_add(struct list_head *new, struct list_head *head)   
  41. {   
  42.     __list_add(new, head, head->next);   
  43. }   
  44.   
  45. .....   
  46.   
  47. /**  
  48. * list_entry - get the struct for this entry  
  49. * @ptr:    the &struct list_head pointer.  
  50. * @type:    the type of the struct this is embedded in.  
  51. * @member:    the name of the list_struct within the struct.  
  52. */  
  53. #define list_entry(ptr, type, member) \   
  54.     container_of(ptr, type, member)   
  55.   
  56. /**  
  57. * list_for_each    -    iterate over a list  
  58. * @pos:    the &struct list_head to use as a loop counter.  
  59. * @head:    the head for your list.  
  60. */  
  61. #define list_for_each(pos, head) \   
  62.     for (pos = (head)->next; prefetch(pos->next), pos != (head); \   
  63.             pos = pos->next)   
  64.   
  65. ......  

  66. ....
  67. struct list_head {
  68.     struct list_head *next, *prev;
  69. };


  70. #define LIST_HEAD_INIT(name) { &(name), &(name) }

  71. #define LIST_HEAD(name) \
  72.     struct list_head name = LIST_HEAD_INIT(name)

  73. #define INIT_LIST_HEAD(ptr) do { \
  74.     (ptr)->next = (ptr); (ptr)->prev = (ptr); \
  75. } while (0)

  76. /*
  77. * Insert a new entry between two known consecutive entries.
  78. *
  79. * This is only for internal list manipulation where we know
  80. * the prev/next entries already!
  81. */
  82. static inline void __list_add(struct list_head *new,
  83.                   struct list_head *prev,
  84.                   struct list_head *next)
  85. {
  86.     next->prev = new;
  87.     new->next = next;
  88.     new->prev = prev;
  89.     prev->next = new;
  90. }

  91. /**
  92. * list_add - add a new entry
  93. * @new: new entry to be added
  94. * @head: list head to add it after
  95. *
  96. * Insert a new entry after the specified head.
  97. * This is good for implementing stacks.
  98. */
  99. static inline void list_add(struct list_head *new, struct list_head *head)
  100. {
  101.     __list_add(new, head, head->next);
  102. }

  103. .....

  104. /**
  105. * list_entry - get the struct for this entry
  106. * @ptr:    the &struct list_head pointer.
  107. * @type:    the type of the struct this is embedded in.
  108. * @member:    the name of the list_struct within the struct.
  109. */
  110. #define list_entry(ptr, type, member) \
  111.     container_of(ptr, type, member)

  112. /**
  113. * list_for_each    -    iterate over a list
  114. * @pos:    the &struct list_head to use as a loop counter.
  115. * @head:    the head for your list.
  116. */
  117. #define list_for_each(pos, head) \
  118.     for (pos = (head)->next; prefetch(pos->next), pos != (head); \
  119.             pos = pos->next)

  120. ......
复制代码


其中 container_of 宏如下:


  1. /**  
  2. * container_of - cast a member of a structure out to the containing structure  
  3. * @ptr:    the pointer to the member.  
  4. * @type:    the type of the container struct this is embedded in.  
  5. * @member:    the name of the member within the struct.  
  6. *  
  7. */  
  8. #define container_of(ptr, type, member) ({            \   
  9.         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \   
  10.         (type *)( (char *)__mptr - offsetof(type,member) );})  

  11. /**
  12. * container_of - cast a member of a structure out to the containing structure
  13. * @ptr:    the pointer to the member.
  14. * @type:    the type of the container struct this is embedded in.
  15. * @member:    the name of the member within the struct.
  16. *
  17. */
  18. #define container_of(ptr, type, member) ({            \
  19.         const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
  20.         (type *)( (char *)__mptr - offsetof(type,member) );})

复制代码


这里使用了GCC特有的 "typeof" 关键字,如果想用其他编译器也想编译通过的话,可以修改成:


  1. #define container_of(ptr, type, member) (            \   
  2.         (type *)( (char *)ptr - offsetof(type,member) ) )  

  3. #define container_of(ptr, type, member) (            \
  4.         (type *)( (char *)ptr - offsetof(type,member) ) )
复制代码

为了便于说明,prefetch定义成:

  1. static inline void prefetch(const void *x) {;}  

  2. static inline void prefetch(const void *x) {;}
复制代码

offsetof的一个简单版本:

  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  

  2. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
复制代码

好了,让我们看看怎么用:

  1. struct my_data {   
  2.     int x;   
  3.     int y;   
  4.     struct list_head list;   
  5. }   
  6.   
  7. /* 链表头 */  
  8. LIST_HEAD(my_listhead);   
  9.   
  10. void my_function()   
  11. {   
  12.     ...   
  13.     /* 节点对象 */  
  14.     struct my_data *node_1 = (struct my_data *) malloc(sizeof(struct my_data));   
  15.     struct my_data *node_2 = (struct my_data *) malloc(sizeof(struct my_data));   
  16.     ...   
  17.     /* 加入链表 */  
  18.     list_add (node_1->list, &my_listhead);   
  19.     list_add (node_2->list, &my_listhead);   
  20.     ...   
  21.     /* 遍历链表 */  
  22.     struct my_data * node;   
  23.     struct list_head *pos;   
  24.     list_for_each (pos, &my_listhead) {   
  25.        node = list_entry (pos, struct my_data, list);   
  26.        ...   
  27.     }  

  28. struct my_data {
  29.     int x;
  30.     int y;
  31.     struct list_head list;
  32. }

  33. /* 链表头 */
  34. LIST_HEAD(my_listhead);

  35. void my_function()
  36. {
  37.     ...
  38.     /* 节点对象 */
  39.     struct my_data *node_1 = (struct my_data *) malloc(sizeof(struct my_data));
  40.     struct my_data *node_2 = (struct my_data *) malloc(sizeof(struct my_data));
  41.     ...
  42.     /* 加入链表 */
  43.     list_add (node_1->list, &my_listhead);
  44.     list_add (node_2->list, &my_listhead);
  45.     ...
  46.     /* 遍历链表 */
  47.     struct my_data * node;
  48.     struct list_head *pos;
  49.     list_for_each (pos, &my_listhead) {
  50.        node = list_entry (pos, struct my_data, list);
  51.        ...
  52.     }
复制代码


其中最精彩的部分是遍历链表的表达方式:
list_for_each (...) {
...
}
这种表达方式另我想起了Ruby,C++ STL中的到处出现的iterator,和VB中的for each...in...next语句。

从内部结构角度来看,Linux的list实现方式有点类似C++中的"组合类"——在需要放入链表的对象内部放入list类(struct list_head)。但是从遍历链表的时候,可以根据list指针得到包含list节点的对象指针来看,又有点超出了"组合类"的范畴。能否把 struct my_data看成继承了struct list_head呢?从内存映像来看倒有点像(C++子类对象的内存映像是父类对象的超级)。当然,这种强行联系完全没有必要,C就是C,何必去往C+ +套呢?C自有C的表达方式

--THE END--

注:这几篇是我原来在MSN SPACE的老blog,实在受不了MSN SPACE的速度,于是搬到了javaeye。写这些东西,只是想和使用C的同志分享自己的体验,也想告诉新学习C的同志,C语言也是很有魅力的

[ 本帖最后由 gawk 于 2008-8-24 10:00 编辑 ]

论坛徽章:
0
4 [报告]
发表于 2008-08-24 09:58 |只看该作者
先进高级OO思想的C实现将会使软件界发生一次天翻地覆的大革命。

论坛徽章:
0
5 [报告]
发表于 2008-08-24 10:04 |只看该作者
用函数指针模拟C++成员函数会有不必要的内存开销和性能损失

论坛徽章:
0
6 [报告]
发表于 2008-08-24 10:34 |只看该作者

回复 #5 ytl 的帖子

多了一次地址的计算?

论坛徽章:
0
7 [报告]
发表于 2008-08-24 10:40 |只看该作者
我靠,说真的,我现在一看到什么用C实现OO就头疼,你们发这些帖子不是明摆着把OIOIC招来吗


[ 本帖最后由 converse 于 2008-8-24 10:41 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2008-08-24 11:08 |只看该作者
提示: 作者被禁止或删除 内容自动屏蔽

论坛徽章:
0
9 [报告]
发表于 2008-08-24 11:10 |只看该作者
ooc是什么?

论坛徽章:
0
10 [报告]
发表于 2008-08-24 11:22 |只看该作者
OIOIC 惹谁了?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP