【问题标题】:Struggling with C coming from Object Oriented land? [closed]与来自面向对象领域的 C 作斗争? [关闭]
【发布时间】:2010-10-15 01:18:10
【问题描述】:

当我遇到编程问题时,我自然会开始在脑海中将它们分解为逻辑对象。谁有什么责任,谁拥有什么,谁从什么得到什么,等等。

我在 C 语言上苦苦挣扎。我只是不知道如何用过程语言做事。

有经验的 C 程序员能否帮助解释我在设计时应该如何考虑我的程序?

例如,我想编写自己的 Semaphore 类。我的程序自然需要一个队列数据结构,我也想自己编写。如果我需要在 Java 或 C# 中执行此操作,我可以简单地快速创建一个 Queue 类并在我的 Semaphore 类中创建它的一个新实例。

但是在 C 中,没有对象。那么我是否必须内联队列数据结构的所有行为?

有人可以帮我“得到它”吗?

相关what is the best way to plan and organize development of an application in c

【问题讨论】:

    标签: c procedural-programming


    【解决方案1】:

    但是在 C 中,没有对象。也一样 我必须内联所有的行为 我的队列数据结构?

    没有。

    这样做。

    1. 根据您对 OO 设计的感觉来定义您的类。

    2. 将类的属性写为 C 语言结构。

    3. 将该结构连同对该结构进行操作的所有函数一起放入头文件中。确保 MyStruct * self 是所有这些“方法函数”的第一个参数。

    4. 编写一个包含所有方法函数主体的 C 模块。

    C 中穷人的 OO。它运行良好。只需遵守纪律,将所有内容放入您需要的结构中——公共和私有实例变量——所有内容。

    一般来说,首先要避免尝试使用私有变量。您没有 OO 编译器的全部功能,因此不要为诸如“私有”或“受保护”之类的低价值特性而烦恼。

    【讨论】:

    • 前导下划线保留,不应使用。
    • 根据您的 api 的定义方式,您还可以使用 PIMPL 上的变体来定义私有变量,或强制转换为/从“char reserved[SOME_SIZE]”,这样用户就永远看不到私有变量是什么变量是。
    • @evan 名称前导下划线仅保留在全局范围内,不适用于结构成员
    • 好点。在执行个人的 OO 时,诸如私有和受保护之类的事情比它们的价值要麻烦得多。
    • 我认为可以在接口声明周围使用#define 和#undef 模拟私有/公共。
    【解决方案2】:

    我会修改 S. Lott 的回答以使用 opaque pointer 来执行结构成员的数据隐藏:

    1. 使用普通的 OO 设计定义您想要的类。
    2. 类的成员变量进入 C 语言结构。
    3. 在头文件中,您不想公开对象的成员变量(因为这些变量在 OO 语言中是“私有的”)。相反,请使用不透明指针,即
      typedef struct mystruct_s *mystruct_t; // first argument to all your methods
    4. 对于您希望“公开”的所有方法,请将它们的签名放入您的 .h 文件中。方法体应该放在 .c 文件中,“私有”方法应该只在 .c 文件中定义,并且声明为静态的,这样它们的符号就不会与其他文件中定义的符号冲突。

    使用此方法不需要像下划线这样的巧妙命名约定,但这意味着您的所有成员变量都是私有的。函数可以是公共的或私有的,尽管公共函数是全局命名空间的一部分,因此您可能希望使用“包”名称来限定它们的名称,例如 mystruct_push()mystruct_pop() 等。

    您还需要明确调用者或库是否负责调用malloc()free()。您很可能会拥有mystruct_t *create()void destroy(mystruct_t *target) 方法。

    【讨论】:

    • 我同意;我投票赞成 S. Lott 的回答,但将我的投票移至此,因为隐藏结构的内容是最好的方法 - 我已经这样做了很多次并且它真的很好地工作。
    【解决方案3】:

    你仍然可以用 C 来思考面向对象。

    您只需要创建一个结构和一组函数,这些函数将指向该结构实例的指针作为其第一个参数。

    至于多态性,您可以将结构的大小作为结构的第一个成员传递,因此您知道如何转换它。

    有一个很棒的pdf of object oriented programming with ANSI-C here

    【讨论】:

      【解决方案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 程序员已经在没有的情况下进行了管理。

      祝你好运!

      【讨论】:

        【解决方案5】:

        查看Lua C api。就 C 接口设计而言,它一直是我的指路明灯。每个函数都将 Lua 状态作为主要参数,成为你的“this”。继承有点棘手,但Chipmunk 设法很好地公开了采用通用形状结构的函数,并计算出通过“klass”实际调用的函数的细节。您通常可以利用 void* 让函数采用不同的类型(结构),就像在 OO 中重载一样。它有时会让人觉得有点老套,但效果很好。

        【讨论】:

          【解决方案6】:

          最初 C++ 只是一个从 C++ 源代码编写 C 代码的编译器;然后由本机 C 编译器编译、链接等。

          因此,所有 OOP 方法都可以在 C 中使用——只是编译器无法帮助您,并且不提供所有编译时功能,例如模板、运算符覆盖、数据隐藏等。

          1. C++“结构”(可能仍然是)等同于所有成员“公共”的“类”。
          2. 成员函数可以实现为结构中的函数指针;这可以提供封装和多态性。 除非您使用工厂,否则构造函数存在于全局范围内。析构函数可以是成员函数。
          3. 使用访问器成员函数,如 getColor()setColor() 可以缓解内部差异并提供一些数据隐藏。如果你真的想要,你可以使用 Brian Bondy 的隐藏宏的建议。
          4. 实际上有很多 FOSS 库提供标准容器——哈希表、动态数组、链表等。

          【讨论】:

            【解决方案7】:

            我赞同做“C 中穷人的 OO”的建议。我还认为您可能会受益于花一些时间来了解 Perl 的 OO 是如何工作的。基本上,在 Perl 中,OO 是通过让解释器为每个方法提供实例作为隐式第一个参数来实现的。您将希望在 C 中显式地执行相同的操作,并使用非常非常好的代码组织,因为编译器不会为您强制执行良好的封装。

            顺便说一句,您可以使用opaque pointers 强制保持结构的成员私有。我似乎记得 GNU 编程标准和建议包括一种技术,通过在传递时将所有内容基本上强制转换为 void*,然后使用 typedef 来命名应该传递的每种特定类型的不透明指针。 (即每个“类”)

            【讨论】:

              【解决方案8】:

              你也可以用 C 来做派生类:

              Derived classes in C - What is your favorite method?

              【讨论】:

                【解决方案9】:

                使用 glib、c 库和 oop http://library.gnome.org/devel/glib/2.20/

                【讨论】:

                  猜你喜欢
                  • 2022-01-08
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-10-13
                  • 2012-03-29
                  • 2011-01-17
                  • 2015-04-23
                  • 1970-01-01
                  • 2012-02-26
                  相关资源
                  最近更新 更多