首页 > 解决方案 > C中vtable的单独结构

问题描述

在 C 中执行 OOP 的自然方法是执行以下操作:

#include <stddef.h>
/* stream operations */
struct _src {
  /** open stream. Return true on success */
  bool (*open)(struct _src *src, const char *fspec);
  /** close stream. Return true on success */
  bool (*close)(struct _src *src);
  /** Returns the actual size of buffer read (<=len), or 0 upon error */
  size_t (*read)(struct _src *src, void *buf, size_t len);
  /* hold the actual FILE* in the case of file stream */
  void *data;
};

有时我看到操作位于单独的结构中,并且设计如下:

#include <stddef.h>
struct _src {
  /* vtable */
  const struct _src_ops *ops;
  /* hold the actual FILE* in the case of file stream */
  void *data;
};

/* stream operations */
struct _src_ops {
  /** open stream. Return true on success */
  bool (*open)(struct _src *src, const char *fspec);
  /** close stream. Return true on success */
  bool (*close)(struct _src *src);
  /** Returns the actual size of buffer read (<=len), or 0 upon error */
  size_t (*read)(struct _src *src, void *buf, size_t len);
};

以一种方式或另一种方式做的全部意义是什么?

标签: coopstructinterface

解决方案


似乎有两个好处:

  • const限定符阻止用户有意或无意地重定向函数指针。这将使函数指针本身成为只读的。
  • 拥有一个指针可以让函数成为一个单独的“单例”实例,因为这些函数对于每个结构对象都是相同的,并且只需要分配一次。

但是,使用函数指针进行 OOP 相当粗糙,并且在您绝对确定需要多态性的情况下才有意义。没有this指针,因此您最终会遇到笨拙的语法,例如foo.func(&foo, ...). 值得注意的是,编写“对象点成员”的可能性是一种语言语法,与 OO 设计本身无关。

总体而言,花费大量精力来实现有点罕见和专门的 OO 概念(继承/多态),同时忽略了更重要的 OO 概念(私有封装),这很奇怪。

根据我的经验,最好只使用普通函数但实现不透明类型并将实例作为参数传递给结构。当你真正需要它时处理继承。


推荐阅读