可能重复:
你能用C编写面向对象的代码吗?
C中的面向对象模式?
我记得刚才读到有人(我认为是Linus Torvalds)谈论C++是一种可怕的语言,以及如何用C编写面向对象的程序.在有时间反思的时候,我真的不知道如何所有面向对象的概念都延续到了C.有些事情是相当明显的.例如:
sizeof参数(例如参数)执行一些voodoo你会如何模仿封装和继承?
我想通过使用存储私有成员的嵌套结构可以模拟封装.它可以相当容易地出现,但也许可以被命名PRIVATE或者同样明显的东西,以表明它不应该从结构外部使用.那继承怎么样?
Tro*_*nic 76
您可以使用常规函数和虚拟表(vtable)实现多态性.这是一个非常简洁的系统,我发明了(基于C++)进行编程练习:
构造函数分配内存,然后调用类初始化内存的init函数.每个init函数还应包含一个静态vtable结构,其中包含虚函数指针(纯虚拟的NULL).派生类init函数在执行任何其他操作之前调用超类init函数.
通过实现虚函数包装器(不要与vtables指向的函数混淆)可以创建一个非常好的API,如下所示(static inline如果你在标题中添加它,则在它前面添加):
int playerGuess(Player* this) { return this->vtable->guess(this); }
Run Code Online (Sandbox Code Playgroud)
单继承可以通过滥用结构的二进制布局来完成: 
请注意,多重继承更加混乱,因为在层次结构类型之间进行转换时,通常需要调整指针值.
其他类型特定的数据也可以添加到虚拟表中.示例包括运行时类型信息(例如,类型名称作为字符串),链接到超类vtable和析构函数链.您可能需要虚拟析构函数,其中派生类析构函数将对象降级为其超类,然后递归调用它的析构函数,依此类推,直到到达基类析构函数并最终释放结构.
封装是通过在player_protected.h中定义结构并在player_protected.c中实现函数(由vtable指向)来完成的,对于派生类也是如此,但这非常笨拙并且会降低性能(因为虚拟包装器不能放入标题),所以我建议反对它.
你会如何模仿封装和继承?
实际上,封装是最容易的部分.封装是一种设计理念,它与语言无关,也与你如何思考问题无关.
例如,Windows FILE api是完全封装的.当您打开文件时,您将获得一个不透明对象,其中包含文件"对象"的所有状态信息.您将此句柄交还给每个文件io apis.封装实际上是远优于C++,因为没有公共的头文件,人们可以看看,看看你的私有变量的名称.
继承更难,但为了使代码面向对象,它根本不是必需的.在某些方面,聚合比继承更好,并且聚合在C中和在C++中一样容易.看到这个的实例.
作为对Neil的回应,请参阅维基百科,了解为什么继承不是多态性所必需的.
在C++编译器可用之前的几年,我们的老人都编写了面向对象的代码,这是一个思维模式而不是工具集.
从高度稍微高一点开始考虑问题而不是像OOP主流所暗示的那样更开放,面向对象编程意味着将对象视为具有相关功能的数据.它并不一定意味着函数必须物理地附加到对象,因为它是支持OOP范例的流行语言,例如在C++中:
struct T
{
int data;
int get_data() const { return data; }
};
Run Code Online (Sandbox Code Playgroud)
我建议仔细看看GTK +对象和类型系统.这是用C编程语言实现的OOP的一个很好的例子:
GTK +实现了自己的自定义对象系统,该系统提供标准的面向对象功能,如继承和虚函数
该协会也可以是合同和传统的.
关于封装和数据隐藏技术,流行和简单的可能是不透明指针(或不透明数据类型) - 你可以传递它,但为了加载或存储任何信息,你必须调用相关的功能,知道如何与隐藏在那个不透明指针后面的对象.
另一个,类似但不同的是Shadow Data类型 - 检查这个链接,Jon Jagger对这个不太知名的技术给出了很好的解释.