Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can definitely write C in a (somewhat) object-oriented style.</p> <p>Encapsulation can be done by keeping the definitions of your structures in the .c file rather than in the associated header. Then the outer world handles your objects by keeping pointers to them, and you provide functions accepting such pointers as the "methods" of your objects.</p> <p>Polymorphism-like behavior can be obtained by using functions pointers, usually grouped within "operations structures", kind of like the "virtual method table" in your C++ objects (or whatever it's called). The ops structure can also include other things such as constants whose value is specific to a given "subclass". The "parent" structure can keep a reference to ops-specific data through a generic <code>void*</code> pointer. Of course the "subclass" could repeat the pattern for multiple levels of inheritance.</p> <p>So, in the example below, <code>struct printer</code> is akin to an abstract class, which can be "derived" by filling out a <code>pr_ops</code> structure, and providing a constructor function wrapping <code>pr_create()</code>. Each subtype will have its own structure which will be "anchored" to the <code>struct printer</code> object through the <code>data</code> generic pointer. This is demontrated by the <code>fileprinter</code> subtype. One could imagine a GUI or socket-based printer, that would be manipulated regardless by the rest of the code as a <code>struct printer *</code> reference.</p> <p>printer.h:</p> <pre><code>struct pr_ops { void (*printline)(void *data, const char *line); void (*cleanup)(void *data); }; struct printer *pr_create(const char *name, const struct output_ops *ops, void *data); void pr_printline(struct printer *pr, const char *line); void pr_delete(struct printer *pr); </code></pre> <p>printer.c:</p> <pre><code>#include "printer.h" ... struct printer { char *name; struct pr_ops *ops; void *data; } /* constructor */ struct printer *pr_create(const char *name, const struct output_ops *ops, void *data) { struct printer *p = malloc(sizeof *p); p-&gt;name = strdup(name); p-&gt;ops = ops; p-&gt;data = data; } void pr_printline(struct printer *p, const char *line) { char *l = malloc(strlen(line) + strlen(p-&gt;name) + 3; sprintf(l, "%s: %s", p-&gt;name, line); p-&gt;ops-&gt;printline(p-&gt;data, l); } void pr_delete(struct printer *p) { p-&gt;ops-&gt;cleanup(p-&gt;data); free(p); } </code></pre> <p>Finally, fileprinter.c:</p> <pre><code>struct fileprinter { FILE *f; int doflush; }; static void filepr_printline(void *data, const char *line) { struct fileprinter *fp = data; fprintf(fp-&gt;f, "%s\n", line); if(fp-&gt;doflush) fflush(fp-&gt;f); } struct printer *filepr_create(const char *name, FILE *f, int doflush) { static const struct ops = { filepr_printline, free, }; struct *fp = malloc(sizeof *fp); fp-&gt;f = f; fp-&gt;doflush = doflush; return pr_create(name, &amp;ops, fp); } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload