32bit_me (32bit_me) wrote,
32bit_me
32bit_me

Categories:

ООП на чистом С

Это оружие рыцарей джедаев. Не такое неуклюжее и неточное, как бластер. Элегантное оружие более цивилизованной эпохи.

В этом посте я хотел бы показать на примере, как можно реализовать на чистом С некоторые концепции ООП, в частности, инкапсуляцию. Гуру языка С не найдут здесь ничего нового, но для кого-то это может быть полезно.

Разбирая код Stm32 HAL, можно увидеть следующий код:

  1. //usbd_cdc.h
  2. typedef struct _USBD_CDC_Itf
  3. {
  4. int8_t (* Init) (void);
  5. int8_t (* DeInit) (void);
  6. int8_t (* Control) (uint8_t cmd, uint8_t* pbuf, uint16_t length);
  7. int8_t (* Receive) (uint8_t* Buf, uint32_t *Len);
  8.  
  9. }USBD_CDC_ItfTypeDef;
  10.  
  11. //usbd_cdc_if.c
  12. static int8_t CDC_Init_FS(void);
  13. static int8_t CDC_DeInit_FS(void);
  14. static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length);
  15. static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len);
  16.  
  17. USBD_CDC_ItfTypeDef USBD_Interface_fops_FS =
  18. {
  19. CDC_Init_FS,
  20. CDC_DeInit_FS,
  21. CDC_Control_FS,
  22. CDC_Receive_FS
  23. };
  24.  
  25. static int8_t CDC_Init_FS(void)
  26. {
  27. ...
  28. }
  29.  
  30. static int8_t CDC_DeInit_FS(void)
  31. {
  32. ...
  33. }
  34.  
  35. static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length)
  36. {
  37. ...
  38. }
  39.  
  40. static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
  41. {
  42. ...
  43. }


То есть создаётся экземпляр структуры с указателями на функции CDC_Init_FS, CDC_DeInit_FS, CDC_Control_FS, CDC_Receive_FS.

Этот объект (экземпляр структуры), таким образом, инкапсулирует некий набор методов, и может быть передан (по указателю) в качестве аргумента в другие функции:

  1. USBD_CDC_RegisterInterface(&hUsbDeviceFS, &USBD_Interface_fops_FS);


Там он сохраняется в pdev->pUserData:

  1. uint8_t USBD_CDC_RegisterInterface (USBD_HandleTypeDef *pdev,
  2. USBD_CDC_ItfTypeDef *fops)
  3. {
  4. uint8_t ret = USBD_FAIL;
  5.  
  6. if(fops != NULL)
  7. {
  8. pdev->pUserData= fops;
  9. ret = USBD_OK;
  10. }
  11.  
  12. return ret;
  13. }


И в дальнейшем может использоваться путём вызова его функций:

  1. ((USBD_CDC_ItfTypeDef *)pdev->pUserData)->Control(hcdc->CmdOpCode,
  2. (uint8_t *)(void *)hcdc->data,
  3. (uint16_t)hcdc->CmdLength);


Хотя в приведённом коде существует только один экземпляр объекта, нет никаких проблем сделать множество экземпляров, и передавать методам указатель на инкапсулирующую их структуру (объект), как это неявно происходит в С++. Если немного поколдовать с макросами, наверняка можно это автоматизировать.

Вот так. В принципе, ничего сложного, на хабре и в других источниках уже давно были статьи, как сделать на чистом С почти полноценное ООП, но напомнить лишний раз не помешает.
Tags: C и C++, программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

  • 20 comments