当我遇到编程问题时,我自然会开始将它们分解为我脑子里的逻辑对象。谁有责任,谁拥有什么,谁来自什么等等。
我正在与C斗争。我只是不知道如何用程序语言做事。
有经验的C程序员可以帮助解释我在设计时如何考虑我的程序吗?
例如,我想编写自己的Semaphore类。我自然需要一个队列的数据结构,我也想自己编写。如果我需要在Java或C#中执行此操作,我可以简单地创建一个快速的Queue类,并在我的Semaphore类中创建它的新实例。
但是在C中,没有对象。那么我是否必须内联我的Queue数据结构的所有行为?
有人可以帮我“搞定”吗?
相关:what is the best way to plan and organize development of an application in c
答案 0 :(得分:30)
但是在C中,没有对象。那样做 我必须内联所有的行为 我的队列数据结构?
没有
这样做。
定义你的课程但你觉得做OO设计很舒服。
将您的类的属性编写为C语言结构。
将该结构放在头文件中,以及在该结构上运行的所有函数。确保MyStruct * self
是所有这些“方法函数”的第一个参数。
使用方法函数的所有主体编写C模块。
穷人在C中的OO效果很好。只需遵守规则,将所有内容放入您需要的结构中 - 公共和私有实例变量 - 一切。
通常,避免尝试首先使用私有变量。您没有OO编译器的全部功能,因此不要担心“私有”或“受保护”等低价值功能。
答案 1 :(得分:17)
我会修改S. Lott的答案,使用opaque pointer来执行结构成员的数据隐藏:
typedef struct mystruct_s *mystruct_t; // first argument to all your methods
使用此方法不需要像下划线那样的聪明命名约定,但这意味着所有成员变量都是私有的。函数可以是公共函数或私有函数,但公共函数它们是全局命名空间的一部分,因此您可能希望使用“包”名称来限定其名称,如mystruct_push()
,mystruct_pop()
等。
如果来电者或图书馆负责致电malloc()
和free()
,您还需要明确说明。您很可能会使用mystruct_t *create()
和void destroy(mystruct_t *target)
方法。
答案 2 :(得分:15)
你仍然可以用C来思考面向对象。
您只需要创建一个结构和一组函数,这些函数将指向该结构的实例的指针作为其第一个参数。
对于多态性,您可以将结构的大小作为结构的第一个成员传递,因此您知道如何转换它。
答案 3 :(得分:4)
我有一段时间从程序化到OO思考,所以我感到痛苦。
我发现为了学习如何创建对象,最好考虑一下它们对调用者的看法。从另一个方面来看,同样的方法可能对您有所帮助。考虑组件的API是什么样的。一种好方法是研究现有的C API(我使用标准Java API作为OO API的一组示例)。
您习惯使用类似这样的队列组件:
import some.package.Queue;
Queue q = new Queue();
q.add(item);
在一个典型的C api中,你会期待更像:
#include <queue.h> // provides queue, make_queue(), queue_add(), others
queue q = make_queue(); // queue is probably a struct, or a struct*
queue_add(q,item);
每当你发现自己在想象对象时,做一个类似的转换。
你可以使用指向函数等的指针,在C中创建类似对象的结构 - 但是成千上万的C程序员已经没有管理过。
祝你好运!答案 4 :(得分:2)
查看Lua C api。就C接口设计而言,它一直是我的指路明灯。每个函数都将Lua状态作为一个主要参数,成为你的“this”。继承有点棘手,但Chipmunk设法做了很好的工作,暴露了采用通用形状结构的函数,并计算出通过“klass”实际调用哪个函数的细节。您可以经常利用void *来使函数采用与OO中重载方式不同的类型(结构)。它有时会感觉有点hackish但效果很好。
答案 5 :(得分:1)
最初C ++只是一个从C ++源代码编写C代码的编译器;然后由原生C编译器编译,链接等等。
因此,所有OOP方法都可以在C中使用 - 它只是编译器无法帮助您,并且不提供所有编译时功能,如模板,运算符覆盖,数据隐藏等。
答案 6 :(得分:0)
我第二次提出做“穷人在C中的OO”的建议。我也认为你可能会花些时间看看Perl的OO是如何工作的。基本上OO是通过让解释器为每个方法提供实例作为隐式第一参数来完成的。您将希望在C中明确地执行相同的操作,并使用真正非常好的代码组织,因为编译器不会为您强制执行良好的封装。
顺便说一下,您可以使用opaque pointers强制保持结构的成员保密。我似乎记得GNU编程标准和建议包括一种技术,通过基本上将所有内容转换为void *来传递它,然后使用typedef来命名应该传递的每个特定类型的不透明指针。 (即每个“类”)
答案 7 :(得分:0)
答案 8 :(得分:0)
您也可以使用C:
来创建派生类答案 9 :(得分:0)
使用glib,c库和oop http://library.gnome.org/devel/glib/2.20/