当前位置:  开发笔记 > 编程语言 > 正文

C语言中的面向对象编程

如何解决《C语言中的面向对象编程》经验,为你挑选了5个好方法。

您可以使用常规函数和虚拟表(vtable)实现多态性.这是一个非常简洁的系统,我发明了(基于C++)进行编程练习:替代文字

构造函数分配内存,然后调用类初始化内存的init函数.每个init函数还应包含一个静态vtable结构,其中包含虚函数指针(纯虚拟的NULL).派生类init函数在执行任何其他操作之前调用超类init函数.

通过实现虚函数包装器(不要与vtables指向的函数混淆)可以创建一个非常好的API,如下所示(static inline如果你在标题中添加它,则在它前面添加):

int playerGuess(Player* this) { return this->vtable->guess(this); }

单继承可以通过滥用结构的二进制布局来完成: 替代文字

请注意,多重继承更加混乱,因为在层次结构类型之间进行转换时,通常需要调整指针值.

其他类型特定的数据也可以添加到虚拟表中.示例包括运行时类型信息(例如,类型名称作为字符串),链接到超类vtable和析构函数链.您可能需要虚拟析构函数,其中派生类析构函数将对象降级为其超类,然后递归调用它的析构函数,依此类推,直到到达基类析构函数并最终释放结构.

封装是通过在player_protected.h中定义结构并在player_protected.c中实现函数(由vtable指向)来完成的,对于派生类也是如此,但这非常笨拙并且会降低性能(因为虚拟包装器不能放入标题),所以我建议反对它.



1> Tronic..:

您可以使用常规函数和虚拟表(vtable)实现多态性.这是一个非常简洁的系统,我发明了(基于C++)进行编程练习:替代文字

构造函数分配内存,然后调用类初始化内存的init函数.每个init函数还应包含一个静态vtable结构,其中包含虚函数指针(纯虚拟的NULL).派生类init函数在执行任何其他操作之前调用超类init函数.

通过实现虚函数包装器(不要与vtables指向的函数混淆)可以创建一个非常好的API,如下所示(static inline如果你在标题中添加它,则在它前面添加):

int playerGuess(Player* this) { return this->vtable->guess(this); }

单继承可以通过滥用结构的二进制布局来完成: 替代文字

请注意,多重继承更加混乱,因为在层次结构类型之间进行转换时,通常需要调整指针值.

其他类型特定的数据也可以添加到虚拟表中.示例包括运行时类型信息(例如,类型名称作为字符串),链接到超类vtable和析构函数链.您可能需要虚拟析构函数,其中派生类析构函数将对象降级为其超类,然后递归调用它的析构函数,依此类推,直到到达基类析构函数并最终释放结构.

封装是通过在player_protected.h中定义结构并在player_protected.c中实现函数(由vtable指向)来完成的,对于派生类也是如此,但这非常笨拙并且会降低性能(因为虚拟包装器不能放入标题),所以我建议反对它.


+1漂亮的照片.
C++也实现了这样的OOP.

2> Kornel Kisie..:

你读过关于这个主题的"圣经"吗?请参阅面向对象的C ...



3> John Knoelle..:

你会如何模仿封装和继承?

实际上,封装是最​​容易的部分.封装是一种设计理念,它与语言无关,也与你如何思考问题无关.

例如,Windows FILE api是完全封装的.当您打开文件时,您将获得一个不透明对象,其中包含文件"对象"的所有状态信息.您将此句柄交还给每个文件io apis.封装实际上是优于C++,因为没有公共的头文件,人们可以看看,看看你的私有变量的名称.

继承更难,但为了使代码面向对象,它根本不是必需的.在某些方面,聚合比继承更好,并且聚合在C中和在C++中一样容易.看到这个的实例.

作为对Neil的回应,请参阅维基百科,了解为什么继承不是多态性所必需的.

在C++编译器可用之前的几年,我们的老人都编写了面向对象的代码,这是一个思维模式而不是工具集.


@Neil:我不认为你经常犯错误,但在这方面你完全错了.继承不是OO的必要特征.您可以通过聚合/委派获得多态性.

4> Chuck..:

Apple的基于C语言的CoreFoundation框架实际上是为了使其"对象"能够作为Objective-C(一种实际的OO语言)中的对象而加倍.该框架的一个相当大的子集是Apple网站上的开源CF-Lite.可能是以这种方式完成的主要操作系统级框架中的有用案例研究.



5> mloskot..:

从高度稍微高一点开始考虑问题而不是像OOP主流所暗示的那样更开放,面向对象编程意味着将对象视为具有相关功能的数据.它并不一定意味着函数必须物理地附加到对象,因为它是支持OOP范例的流行语言,例如在C++中:

struct T
{
   int data;
   int get_data() const { return data; }
};

我建议仔细看看GTK +对象和类型系统.这是用C编程语言实现的OOP的一个很好的例子:

GTK +实现了自己的自定义对象系统,该系统提供标准的面向对象功能,如继承和虚函数

该协会也可以是合同和传统的.

关于封装和数据隐藏技术,流行和简单的可能是不透明指针(或不透明数据类型) - 你可以传递它,但为了加载或存储任何信息,你必须调用相关的功能,知道如何与隐藏在那个不透明指针后面的对象.

另一个,类似但不同的是Shadow Data类型 - 检查这个链接,Jon Jagger对这个不太知名的技术给出了很好的解释.

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有