C面向对象

Edit


曾经谈到面相对象,就是C++,之后最多加上Java。后来,读过的书上说,面向对象其实只是一种设计方式——万事即对象,而不在乎用的是什么语言。C语言,一样也可以做面向对象设计,有时候还更自由,没有C++的各种隐藏的坑。这篇笔记就具体说说如何用C来做面向对象。
开始之前,用一篇网上收录的笔记作为入门:用C语言写面向的对象是一种什么样的体验

封装

对类结构的封装,C里面用struct,相比C++缺少的就是:

  • 构造函数和析构函数
  • private & protect
/** Class definition of BaseLed.
* The concrete LED class should inherit from this class.
*/
typedef struct BaseLed
{
uint8_t id;
/**
* Below 4 members are used to record the LED blinking state.
*/
LedState state;
uint16_t onTime;
uint16_t offTime;
uint16_t blinkCount;
/**
* Public function members.
*/
bool (*init)(struct BaseLed*, uint8_t); //!< Init hardware if needed
void (*switchit)(struct BaseLed*, LedState); //!< Turn on/off
void (*set_brightness)(struct BaseLed*, uint8_t); //!< Set LED's brightness level
}BaseLed;

上面的例子,上半部分是成员变量,下半部分是成员函数。

构造函数&析构函数

C++中,构造函数在以下情况中调用:

  • 比如你在main里面声明了一个类A..那么~A()会在main结束时调用
  • 如果在自定义的函数f()里面声明了一个A 函数f结束的时候就会调用~A()
  • 或者你delete 指向A的指针..
  • 或者显式的调用析构函数

C++各种隐藏的坑,参考网页那些被C++默默地声明和调用的函数

在C面向对象里面,就没有这种问题,因为C语言根本不会为你生成隐藏的函数,也不会帮你调用构造函数,分配内存之类的,也没有虚函数表(VTable)。所有这一切都得自己亲力亲为。不过这样也好,所见即所得嘛。

// ClassA.h
typedef struct _ClassA
{
int a;
void (*funcA)(struct _ClassA*, int);
}ClassA;
ClassA* newA(int);
void deleteA(ClassA*)
// ClassA.c
#include <ClassA.h>
void funcA(ClassA* thisObj, int a)
{
}
ClassA* newA(int a)
{
ClassA* Aobj = malloc(sizeof(ClassA));
Aobj->funcA = funcA;
Aobj->a = a;
}
void deleteA(ClassA* obj)
{
free(obj);
}
// main.c
#include <ClassA.h>
void main()
{
ClassA* aobj = newA(0);
}

在头文件中定义结构体,在.c文件中定义成员函数,在需要调用的地方include对应的头文件。注意,当main函数和ClassA定义在不同的lib中时,头文件中的newA, deleteA需要定义为extern。

访问控制——private & protect

上面的例子是最基本的封装定义。C++中最有趣的是访问控制,即隐藏具体实现,而只暴露接口。

private

怎么做到private呢?用结构体把private包起来。

// ClassA.c
#include <ClassA_Private.h>
#include <ClassA.h>
ClassA* newA(int a)
{
ClassA* pA = malloc(sizeof(ClassA));
pA->private_data = malloc(sizeof(ClassA_Private));
ClassA_Private* pPrivate = (ClassA_Private*)(pA->private_data);
pPrivate->private_a = a;
}
...
// ClassA.h
typedef struct _ClassA
{
int a;
void (*funcA)(struct _ClassA*, int);
void* private_data; // void pointer hide all details
}ClassA;
// ClassA_Private.h
struct _ClassA;
typedef _ClassA_Private
{
int private_a;
void (*private_funcA)(struct _ClassA*, int);
}ClassA_Private
// main.c
#include <ClassA.h>
void main()
{
ClassA* obj = newA(0);
// Below line will bring compile error.
// obj->private_data.private_funcA
}

将不想暴露的数据放在一个结构体中,类定义的头文件包含该头文件。对于想隐藏的客户代码,不暴露该头文件,则其不能引用该private代码。

protect

protect数据是只能暴露给子类和友元,关于友元,参考【C++基础之十】友元函数和友元类
在C里面,就没这么多花头了,“对于想隐藏的客户代码,不暴露该头文件”。

// ChildClassA.h
#include <BaseClassA.h>
#include <BaseClassA_Private.h>
typedef struct _ChildClassA
{
BaseClassA parent;
...
}
// FriendClassA.h
#include <BaseClassA.h>
#include <BaseClassA_Private.h>
typedef struct _ChildClassA
{
BaseClassA parent;
...
}
// main.c
#include <BaseClassA.h>

继承

上面已经看到继承的基本代码了,但是为了实现标准的继承我们还要做的更多。

// BaseClassA
typedef struct BaseClass
{
int a;
void (*funcA)(struct BaseClassA*, int);
}BaseClassA;
// DerivedClassB
#include <BaseClassA.h>
typedef struct DerivedClassB
{
BaseClassA parent;
int special;
void (*funcA)(struct DerivedClassB*, int);
void (*funcB)(struct DerivedClassB*, int);
}DerivedClassB;
DerivedClassB* NewB()
{
DerivedClassB* newB = malloc(sizeof(DerivedClassB));
newB->parent.funcA = funcA;
newB->funcA = funcA;
return newB;
}

子类包含父类的实例,这样就实现了继承。子类同名函数重写了父类同名函数。为下面多态做好准备。

多态

接着上面的例子

BaseClassA* pBase = (BaseClassA*)NewB();
pBase->funcA(); // 调用的是子类构造函数中赋予的函数,这就是多态了

例子

%23C%u9762%u5411%u5BF9%u8C61%0A@%28myblog%29%5Bc/c++%2C%20%u9762%u5411%u5BF9%u8C61%5D%0A%u66FE%u7ECF%u8C08%u5230%u9762%u76F8%u5BF9%u8C61%uFF0C%u5C31%u662FC++%uFF0C%u4E4B%u540E%u6700%u591A%u52A0%u4E0AJava%u3002%u540E%u6765%uFF0C%u8BFB%u8FC7%u7684%u4E66%u4E0A%u8BF4%uFF0C%u9762%u5411%u5BF9%u8C61%u5176%u5B9E%u53EA%u662F%u4E00%u79CD%u8BBE%u8BA1%u65B9%u5F0F%u2014%u2014%u4E07%u4E8B%u5373%u5BF9%u8C61%uFF0C%u800C%u4E0D%u5728%u4E4E%u7528%u7684%u662F%u4EC0%u4E48%u8BED%u8A00%u3002C%u8BED%u8A00%uFF0C%u4E00%u6837%u4E5F%u53EF%u4EE5%u505A%u9762%u5411%u5BF9%u8C61%u8BBE%u8BA1%uFF0C%u6709%u65F6%u5019%u8FD8%u66F4%u81EA%u7531%uFF0C%u6CA1%u6709C++%u7684%u5404%u79CD%u9690%u85CF%u7684%u5751%u3002%u8FD9%u7BC7%u7B14%u8BB0%u5C31%u5177%u4F53%u8BF4%u8BF4%u5982%u4F55%u7528C%u6765%u505A%u9762%u5411%u5BF9%u8C61%u3002%0A%u5F00%u59CB%u4E4B%u524D%uFF0C%u7528%u4E00%u7BC7%u7F51%u4E0A%u6536%u5F55%u7684%u7B14%u8BB0%u4F5C%u4E3A%u5165%u95E8%uFF1A%5B%u7528C%u8BED%u8A00%u5199%u9762%u5411%u7684%u5BF9%u8C61%u662F%u4E00%u79CD%u4EC0%u4E48%u6837%u7684%u4F53%u9A8C%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/29001a8f-6996-413e-b6ad-41c3cbba9c00%29%u3002%0A%0A%5BTOC%5D%0A%0A%23%23%u5C01%u88C5%0A%u5BF9%u7C7B%u7ED3%u6784%u7684%u5C01%u88C5%uFF0CC%u91CC%u9762%u7528%60struct%60%2C%u76F8%u6BD4C++%u7F3A%u5C11%u7684%u5C31%u662F%uFF1A%0A-%20%u6784%u9020%u51FD%u6570%u548C%u6790%u6784%u51FD%u6570%0A-%20private%20%26%20protect%0A%60%60%60%0A/**%20Class%20definition%20of%20BaseLed.%0A%20*%20%20The%20concrete%20LED%20class%20should%20inherit%20from%20this%20class.%0A%20*/%0Atypedef%20struct%20BaseLed%0A%7B%0A%20%20%20%20uint8_t%20id%3B%0A%20%20%20%20/**%0A%20%20%20%20%20*%20Below%204%20members%20are%20used%20to%20record%20the%20LED%20blinking%20state.%0A%20%20%20%20%20*/%0A%20%20%20%20LedState%20state%3B%20%20%20%20%20%20%20%20%20%0A%20%20%20%20uint16_t%20onTime%3B%0A%20%20%20%20uint16_t%20offTime%3B%0A%20%20%20%20uint16_t%20blinkCount%3B%0A%0A%20%20%20%20/**%0A%20%20%20%20%20*%20Public%20function%20members.%0A%20%20%20%20%20*/%0A%20%20%20%20bool%20%28*init%29%28struct%20BaseLed*%2C%20uint8_t%29%3B%20%20%20%20%20%20%20%20%20%20%20%20%20//%21%3C%20Init%20hardware%20if%20needed%0A%20%20%20%20void%20%28*switchit%29%28struct%20BaseLed*%2C%20LedState%29%3B%20%20%20%20%20%20%20%20//%21%3C%20Turn%20on/off%0A%20%20%20%20void%20%28*set_brightness%29%28struct%20BaseLed*%2C%20uint8_t%29%3B%20%20%20//%21%3C%20Set%20LED%27s%20brightness%20level%0A%7DBaseLed%3B%0A%60%60%60%0A%u4E0A%u9762%u7684%u4F8B%u5B50%uFF0C%u4E0A%u534A%u90E8%u5206%u662F%u6210%u5458%u53D8%u91CF%uFF0C%u4E0B%u534A%u90E8%u5206%u662F%u6210%u5458%u51FD%u6570%u3002%0A%23%23%23%u6784%u9020%u51FD%u6570%26%u6790%u6784%u51FD%u6570%0AC++%u4E2D%uFF0C%u6784%u9020%u51FD%u6570%u5728%u4EE5%u4E0B%u60C5%u51B5%u4E2D%u8C03%u7528%uFF1A%0A%3E*%20%u6BD4%u5982%u4F60%u5728main%u91CC%u9762%u58F0%u660E%u4E86%u4E00%u4E2A%u7C7BA..%u90A3%u4E48%7EA%28%29%u4F1A%u5728main%u7ED3%u675F%u65F6%u8C03%u7528%0A%3E*%20%u5982%u679C%u5728%u81EA%u5B9A%u4E49%u7684%u51FD%u6570f%28%29%u91CC%u9762%u58F0%u660E%u4E86%u4E00%u4E2AA%20%20%u51FD%u6570f%u7ED3%u675F%u7684%u65F6%u5019%u5C31%u4F1A%u8C03%u7528%7EA%28%29%0A%3E*%20%u6216%u8005%u4F60delete%20%u6307%u5411A%u7684%u6307%u9488..%0A%3E*%20%u6216%u8005%u663E%u5F0F%u7684%u8C03%u7528%u6790%u6784%u51FD%u6570%0A%0AC++%u5404%u79CD%u9690%u85CF%u7684%u5751%uFF0C%u53C2%u8003%u7F51%u9875%5B%u90A3%u4E9B%u88ABC++%u9ED8%u9ED8%u5730%u58F0%u660E%u548C%u8C03%u7528%u7684%u51FD%u6570%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/86f265a4-1139-468b-a941-1897a54ae440%29%0A%0A%u5728C%u9762%u5411%u5BF9%u8C61%u91CC%u9762%uFF0C%u5C31%u6CA1%u6709%u8FD9%u79CD%u95EE%u9898%uFF0C%u56E0%u4E3AC%u8BED%u8A00%u6839%u672C%u4E0D%u4F1A%u4E3A%u4F60%u751F%u6210%u9690%u85CF%u7684%u51FD%u6570%uFF0C%u4E5F%u4E0D%u4F1A%u5E2E%u4F60%u8C03%u7528%u6784%u9020%u51FD%u6570%uFF0C%u5206%u914D%u5185%u5B58%u4E4B%u7C7B%u7684%uFF0C%u4E5F%u6CA1%u6709%u865A%u51FD%u6570%u8868%28VTable%29%u3002%u6240%u6709%u8FD9%u4E00%u5207%u90FD%u5F97%u81EA%u5DF1%u4EB2%u529B%u4EB2%u4E3A%u3002%u4E0D%u8FC7%u8FD9%u6837%u4E5F%u597D%uFF0C%u6240%u89C1%u5373%u6240%u5F97%u561B%u3002%0A%60%60%60%0A//%20ClassA.h%0Atypedef%20struct%20_ClassA%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%7DClassA%3B%0A%0AClassA*%20newA%28int%29%3B%0Avoid%20deleteA%28ClassA*%29%0A%0A//%20ClassA.c%0A%23include%20%3CClassA.h%3E%0Avoid%20funcA%28ClassA*%20thisObj%2C%20int%20a%29%0A%7B%0A%7D%0A%0AClassA*%20newA%28int%20a%29%0A%7B%0A%09ClassA*%20Aobj%20%3D%20malloc%28sizeof%28ClassA%29%29%3B%0A%09Aobj-%3EfuncA%20%3D%20funcA%3B%0A%09Aobj-%3Ea%20%3D%20a%3B%0A%7D%0A%0Avoid%20deleteA%28ClassA*%20obj%29%0A%7B%0A%09free%28obj%29%3B%0A%7D%0A//%20main.c%0A%23include%20%3CClassA.h%3E%0Avoid%20main%28%29%0A%7B%0A%09ClassA*%20aobj%20%3D%20newA%280%29%3B%0A%7D%0A%60%60%60%0A%u5728%u5934%u6587%u4EF6%u4E2D%u5B9A%u4E49%u7ED3%u6784%u4F53%uFF0C%u5728.c%u6587%u4EF6%u4E2D%u5B9A%u4E49%u6210%u5458%u51FD%u6570%uFF0C%u5728%u9700%u8981%u8C03%u7528%u7684%u5730%u65B9include%u5BF9%u5E94%u7684%u5934%u6587%u4EF6%u3002%u6CE8%u610F%uFF0C%u5F53%60main%60%u51FD%u6570%u548CClassA%u5B9A%u4E49%u5728%u4E0D%u540C%u7684lib%u4E2D%u65F6%uFF0C%u5934%u6587%u4EF6%u4E2D%u7684newA%2C%20deleteA%u9700%u8981%u5B9A%u4E49%u4E3Aextern%u3002%0A%0A%23%23%23%u8BBF%u95EE%u63A7%u5236%u2014%u2014private%20%26%20protect%0A%u4E0A%u9762%u7684%u4F8B%u5B50%u662F%u6700%u57FA%u672C%u7684%u5C01%u88C5%u5B9A%u4E49%u3002C++%u4E2D%u6700%u6709%u8DA3%u7684%u662F%u8BBF%u95EE%u63A7%u5236%uFF0C%u5373%u9690%u85CF%u5177%u4F53%u5B9E%u73B0%uFF0C%u800C%u53EA%u66B4%u9732%u63A5%u53E3%u3002%0A%23%23%23%23private%0A%u600E%u4E48%u505A%u5230private%u5462%uFF1F%u7528%u7ED3%u6784%u4F53%u628Aprivate%u5305%u8D77%u6765%u3002%0A%60%60%60cpp%0A//%20ClassA.c%0A%23include%20%3CClassA_Private.h%3E%0A%23include%20%3CClassA.h%3E%0AClassA*%20newA%28int%20a%29%0A%7B%0A%09ClassA*%20pA%20%3D%20malloc%28sizeof%28ClassA%29%29%3B%0A%09pA-%3Eprivate_data%20%3D%20malloc%28sizeof%28ClassA_Private%29%29%3B%0A%09ClassA_Private*%20pPrivate%20%3D%20%28ClassA_Private*%29%28pA-%3Eprivate_data%29%3B%0A%09pPrivate-%3Eprivate_a%20%3D%20a%3B%0A%7D%0A...%0A%60%60%60%0A%60%60%60%0A//%20ClassA.h%0Atypedef%20struct%20_ClassA%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%09void*%20private_data%3B%20%20//%20void%20pointer%20hide%20all%20details%0A%7DClassA%3B%0A%60%60%60%0A%60%60%60%0A//%20ClassA_Private.h%0Astruct%20_ClassA%3B%0Atypedef%20_ClassA_Private%0A%7B%0A%09int%20private_a%3B%0A%09void%20%28*private_funcA%29%28struct%20_ClassA*%2C%20int%29%3B%0A%7DClassA_Private%0A%60%60%60%0A%0A%60%60%60%0A//%20main.c%0A%23include%20%3CClassA.h%3E%0Avoid%20main%28%29%0A%7B%0A%09ClassA*%20obj%20%3D%20newA%280%29%3B%0A%09//%20Below%20line%20will%20bring%20compile%20error.%0A%09//%20obj-%3Eprivate_data.private_funcA%0A%7D%0A%60%60%60%0A%u5C06%u4E0D%u60F3%u66B4%u9732%u7684%u6570%u636E%u653E%u5728%u4E00%u4E2A%u7ED3%u6784%u4F53%u4E2D%uFF0C%u7C7B%u5B9A%u4E49%u7684%u5934%u6587%u4EF6%u5305%u542B%u8BE5%u5934%u6587%u4EF6%u3002%u5BF9%u4E8E%u60F3%u9690%u85CF%u7684%u5BA2%u6237%u4EE3%u7801%uFF0C%u4E0D%u66B4%u9732%u8BE5%u5934%u6587%u4EF6%uFF0C%u5219%u5176%u4E0D%u80FD%u5F15%u7528%u8BE5private%u4EE3%u7801%u3002%0A%23%23%23protect%0Aprotect%u6570%u636E%u662F%u53EA%u80FD%u66B4%u9732%u7ED9%u5B50%u7C7B%u548C%u53CB%u5143%uFF0C%u5173%u4E8E%u53CB%u5143%uFF0C%u53C2%u8003%5B%u3010C++%u57FA%u7840%u4E4B%u5341%u3011%u53CB%u5143%u51FD%u6570%u548C%u53CB%u5143%u7C7B%5D%28https%3A//app.yinxiang.com/shard/s10/nl/161681/b14c761f-a0d8-4c31-b54c-fb0f4a369aae%29%0A%u5728C%u91CC%u9762%uFF0C%u5C31%u6CA1%u8FD9%u4E48%u591A%u82B1%u5934%u4E86%uFF0C%u201C%u5BF9%u4E8E%u60F3%u9690%u85CF%u7684%u5BA2%u6237%u4EE3%u7801%uFF0C%u4E0D%u66B4%u9732%u8BE5%u5934%u6587%u4EF6%u201D%u3002%0A%60%60%60%0A//%20ChildClassA.h%0A%23include%20%3CBaseClassA.h%3E%0A%23include%20%3CBaseClassA_Private.h%3E%0Atypedef%20struct%20_ChildClassA%0A%7B%0A%09BaseClassA%20parent%3B%0A%09...%0A%7D%0A%0A//%20FriendClassA.h%0A%23include%20%3CBaseClassA.h%3E%0A%23include%20%3CBaseClassA_Private.h%3E%0Atypedef%20struct%20_ChildClassA%0A%7B%0A%09BaseClassA%20parent%3B%0A%09...%0A%7D%0A%0A//%20main.c%0A%23include%20%3CBaseClassA.h%3E%0A%60%60%60%0A%23%23%u7EE7%u627F%0A%u4E0A%u9762%u5DF2%u7ECF%u770B%u5230%u7EE7%u627F%u7684%u57FA%u672C%u4EE3%u7801%u4E86%uFF0C%u4F46%u662F%u4E3A%u4E86%u5B9E%u73B0%u6807%u51C6%u7684%u7EE7%u627F%u6211%u4EEC%u8FD8%u8981%u505A%u7684%u66F4%u591A%u3002%0A%60%60%60%0A//%20BaseClassA%0Atypedef%20struct%20BaseClass%0A%7B%0A%09int%20a%3B%0A%09void%20%28*funcA%29%28struct%20BaseClassA*%2C%20int%29%3B%0A%7DBaseClassA%3B%0A%0A//%20DerivedClassB%0A%23include%20%3CBaseClassA.h%3E%0Atypedef%20struct%20DerivedClassB%0A%7B%0A%09BaseClassA%20parent%3B%0A%09int%20special%3B%0A%09void%20%28*funcA%29%28struct%20DerivedClassB*%2C%20int%29%3B%0A%09void%20%28*funcB%29%28struct%20DerivedClassB*%2C%20int%29%3B%0A%7DDerivedClassB%3B%0A%0ADerivedClassB*%20NewB%28%29%0A%7B%0A%09DerivedClassB*%20newB%20%3D%20malloc%28sizeof%28DerivedClassB%29%29%3B%0A%09newB-%3Eparent.funcA%20%3D%20funcA%3B%0A%09newB-%3EfuncA%20%3D%20funcA%3B%0A%09return%20newB%3B%0A%7D%0A%60%60%60%0A%u5B50%u7C7B%u5305%u542B%u7236%u7C7B%u7684%u5B9E%u4F8B%uFF0C%u8FD9%u6837%u5C31%u5B9E%u73B0%u4E86%u7EE7%u627F%u3002%u5B50%u7C7B%u540C%u540D%u51FD%u6570%u91CD%u5199%u4E86%u7236%u7C7B%u540C%u540D%u51FD%u6570%u3002%u4E3A%u4E0B%u9762%u591A%u6001%u505A%u597D%u51C6%u5907%u3002%0A%23%23%u591A%u6001%0A%u63A5%u7740%u4E0A%u9762%u7684%u4F8B%u5B50%0A%60%60%60%0ABaseClassA*%20pBase%20%3D%20%28BaseClassA*%29NewB%28%29%3B%0ApBase-%3EfuncA%28%29%3B%20//%20%u8C03%u7528%u7684%u662F%u5B50%u7C7B%u6784%u9020%u51FD%u6570%u4E2D%u8D4B%u4E88%u7684%u51FD%u6570%uFF0C%u8FD9%u5C31%u662F%u591A%u6001%u4E86%0A%60%60%60%0A%23%23%u4F8B%u5B50%0A