如何在C中实现类? 假设我必须使用C(No.C++或面向对象编译器),并且我没有动态内存分配,我可以用什么技术来实现一个类,或者一个类的好近似?将“类”隔离到单独的文件总是一个好主意吗?假设我们可以通过假设固定数量的实例来预先分配内存,甚至在编译之前将对每个对象的引用定义为常量。请随意假设我需要实现哪一个OOP概念(它会有所不同),并为每个概念提出最佳方法

如何在C中实现类? 假设我必须使用C(No.C++或面向对象编译器),并且我没有动态内存分配,我可以用什么技术来实现一个类,或者一个类的好近似?将“类”隔离到单独的文件总是一个好主意吗?假设我们可以通过假设固定数量的实例来预先分配内存,甚至在编译之前将对每个对象的引用定义为常量。请随意假设我需要实现哪一个OOP概念(它会有所不同),并为每个概念提出最佳方法,c,class,oop,embedded,C,Class,Oop,Embedded,限制: 我必须使用C,而不是OOP 因为我正在为一个 嵌入式系统,以及编译器和 先前存在的代码库是C语言 没有动态内存分配 因为我们没有足够的记忆 合理地假设我们不会用完 如果我们开始动态分配 它 我们使用的编译器在函数指针方面没有问题 我的方法是将结构和所有主要相关函数移动到一个单独的源文件中,以便“可移植”地使用 根据您的编译器,您可能能够将函数包含到结构中,但这是一个非常特定于编译器的扩展,与我经常使用的标准的最新版本无关:)正如您正确指出的,C不是一种OOP语言,因此,没有内置的方法来

限制:

  • 我必须使用C,而不是OOP 因为我正在为一个 嵌入式系统,以及编译器和 先前存在的代码库是C语言
  • 没有动态内存分配 因为我们没有足够的记忆 合理地假设我们不会用完 如果我们开始动态分配 它
  • 我们使用的编译器在函数指针方面没有问题

我的方法是将
结构和所有主要相关函数移动到一个单独的源文件中,以便“可移植”地使用


根据您的编译器,您可能能够将函数包含到
结构中,但这是一个非常特定于编译器的扩展,与我经常使用的标准的最新版本无关:)

正如您正确指出的,C不是一种OOP语言,因此,没有内置的方法来编写真正的类。最好的办法是查看,这些将让您构建一个类的近似值。但是,由于C是过程性的,您可能需要考虑编写更多的类C代码(即不尝试使用类)。

也可以使用C,可以直接使用C++并得到类。

在这种情况下,类的良好逼近可以是AN。但它仍然不一样。

这取决于您想要的确切的“面向对象”功能集。如果需要重载和/或虚拟方法之类的东西,可能需要在结构中包含函数指针:

typedef struct {
  float (*computeArea)(const ShapeClass *shape);
} ShapeClass;

float shape_computeArea(const ShapeClass *shape)
{
  return shape->computeArea(shape);
}
这将允许您通过“继承”基类并实现适当的函数来实现类:

typedef struct {
  ShapeClass shape;
  float width, height;
} RectangleClass;

static float rectangle_computeArea(const ShapeClass *shape)
{
  const RectangleClass *rect = (const RectangleClass *) shape;
  return rect->width * rect->height;
}
void rectangle_new_with_lengths(RectangleClass *rect, float width, float height)
{
  rectangle_new(rect);
  rect->width = width;
  rect->height = height;
}
当然,这还需要实现一个构造函数,以确保函数指针设置正确。通常,您会为实例动态分配内存,但也可以让调用者这样做:

void rectangle_new(RectangleClass *rect)
{
  rect->width = rect->height = 0.f;
  rect->shape.computeArea = rectangle_computeArea;
}
如果需要几个不同的构造函数,则必须“修饰”函数名,不能有多个
rectangle\u new()
函数:

typedef struct {
  ShapeClass shape;
  float width, height;
} RectangleClass;

static float rectangle_computeArea(const ShapeClass *shape)
{
  const RectangleClass *rect = (const RectangleClass *) shape;
  return rect->width * rect->height;
}
void rectangle_new_with_lengths(RectangleClass *rect, float width, float height)
{
  rectangle_new(rect);
  rect->width = width;
  rect->height = height;
}
下面是一个显示用法的基本示例:

int main(void)
{
  RectangleClass r1;

  rectangle_new_with_lengths(&r1, 4.f, 5.f);
  printf("rectangle r1's area is %f units square\n", shape_computeArea(&r1));
  return 0;
}
我希望这至少能给你一些想法。要在C中获得成功且丰富的面向对象框架,请查看glib的库


还注意到上面没有建模的“类”,每个对象都有自己的方法指针,它比C++中通常发现的更灵活一些。此外,它还需要内存。您可以通过将方法指针填充到

结构中,并为每个对象实例创建一种引用类的方法来避免这种情况。

您想要虚拟方法吗

如果不是,那么您只需在结构本身中定义一组函数指针。如果你把所有的函数指针分配给标准的C函数,那么你就可以用非常相似的语法调用C函数,而不是C++下的函数。 如果你想要虚拟方法,它会变得更复杂。基本上,您需要为每个结构实现自己的VTable,并根据调用的函数为VTable分配函数指针。然后,在结构本身中需要一组函数指针,这些指针反过来调用VTable中的函数指针。这基本上是C++所做的。< /P>
不过。。。如果你想要后者,那么你最好找到一个C++编译器,你可以使用和重新编译项目。我从来没有理解过对C++的迷恋在嵌入式中不可用。我已经用过很多次了,它工作速度很快,没有内存问题。当然,你必须对你所做的事情更加小心一点,但其实并没有那么复杂。

使用
结构来模拟类的数据成员。就方法范围而言,您可以通过将私有函数原型放在.c文件中,将公共函数放在.h文件中来模拟私有方法。

我也不得不做一次,作为家庭作业。我采用了这种方法:

  • 在数据库中定义数据成员 结构
  • 定义您的函数成员 将指向结构的指针作为 第一个论点
  • 在一个标题和一个c中执行这些操作。 结构定义的标题& 函数声明,用于 实现
  • 一个简单的例子是:

    /// Queue.h
    struct Queue
    {
        /// members
    }
    typedef struct Queue Queue;
    
    void push(Queue* q, int element);
    void pop(Queue* q);
    // etc.
    /// 
    

    如果只需要一个类,请使用
    struct
    s数组作为“对象”数据,并将指向它们的指针传递给“成员”函数。在声明
    struct\u which
    之前,可以使用
    typedef struct\u which
    对客户端代码隐藏实现。这种“对象”与C标准库
    文件
    对象之间没有区别

    如果您想要多个具有继承和虚拟函数的类,那么通常会有指向作为结构成员的函数的指针,或者指向虚拟函数表的共享指针。该库同时使用了这个和typedef技巧,并且被广泛使用


    网上还有一本关于这方面技术的书-

    > P >第一个C++编译器实际上是一个预处理器,它将C++代码转换成C.< 所以很可能会有C语言的类。
    您可能会尝试挖掘一个旧的C++预处理器,看看它创建了什么样的解决方案。

    < p>您可以查看GOBEKET。它是一个操作系统库,为您提供了一种处理对象的详细方式

    我的策略是:

    • 定义类中的所有代码
      /// Object.h
      typedef struct Object {
          uuid_t uuid;
      } Object;
      
      int Object_init(Object *self);
      uuid_t Object_get_uuid(Object *self);
      int Object_clean(Object *self);
      
      /// Person.h
      typedef struct Person {
          Object obj;
          char *name;
      } Person;
      
      int Person_init(Person *self, char *name);
      int Person_greet(Person *self);
      int Person_clean(Person *self);
      
      /// Object.c
      #include "object.h"
      
      int Object_init(Object *self)
      {
          self->uuid = uuid_new();
      
          return 0;
      }
      uuid_t Object_get_uuid(Object *self)
      { // Don't actually create getters in C...
          return self->uuid;
      }
      int Object_clean(Object *self)
      {
          uuid_free(self->uuid);
      
          return 0;
      }
      
      /// Person.c
      #include "person.h"
      
      int Person_init(Person *self, char *name)
      {
          Object_init(&self->obj); // Or just Object_init(&self);
          self->name = strdup(name);
      
          return 0;
      }
      int Person_greet(Person *self)
      {
          printf("Hello, %s", self->name);
      
          return 0;
      }
      int Person_clean(Person *self)
      {
          free(self->name);
          Object_clean(self);
      
          return 0;
      }
      
      /// main.c
      int main(void)
      {
          Person p;
      
          Person_init(&p, "John");
          Person_greet(&p);
          Object_get_uuid(&p); // Inherited function
          Person_clean(&p);
      
          return 0;
      }