7

Possible Duplicate:
How could one implement C++ virtual functions in C

In C++ the only difference between a class and a struct is the default access level. So you can have virtual functions in structures, inherit from structures and so on. My question is, can you also do this in C?

Community
  • 1
  • 1
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 3
    See [How could one implement C++ virtual functions in C](http://stackoverflow.com/questions/3113583/how-could-one-implement-c-virtual-functions-in-c) – Péter Török Jul 27 '11 at 12:47
  • I know how they are implemented in C++, just wondering if it worked in C. I didn't know that virtual was not a keyword in C and all google searches led me to c++ stuff... – Luchian Grigore Jul 27 '11 at 12:49
  • 1
    That is not "the only difference", they also differ in their default inheritance. C does not support member functions of any type - virtual or otherwise. – Clifford Jul 27 '11 at 13:29
  • To put it short your question makes not much sense, C `struct` don't have member function. C doesn't have apples, so it is useless to ask if it has green apples. – Jens Gustedt Jul 27 '11 at 13:43
  • Well, I didn't know C structs don't have functions... – Luchian Grigore Jul 27 '11 at 13:44
  • 1
    @Luchian: Welcome to SO. Don't get dismayed if this question is closed as it was already asked previously (at least twice). See the linked question that Peter provided. –  Jul 27 '11 at 14:46
  • I like the fact that the question was closed as a duplicate of a question close as a duplicate of a question closed as a duplicate (shortest path, another one gives an extra indirection). There should be a badge for this. – André Caron Jul 27 '11 at 15:43

5 Answers5

12

You can do "virtual functions" with function pointers stored in your structs. For inheratince, you can embed a struct in another struct but the syntax, again, is going to be different than what you would expect. You can write object-oriented programs in C (classic example is the unix file/socket/... API), but with a quite awkward syntax.

Relevant answers here: https://stackoverflow.com/search?q=C+virtual+functions

Community
  • 1
  • 1
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • 2
    Indeed - the Linux kernel does this quite a lot. A `struct` that contains multiple function pointers (i.e. the `interface`). Each implementation can choose to have only some of the function pointers assigned; the rest are NULL. – Eli Iser Jul 27 '11 at 12:48
  • I knew that, just wondering if you can have virtual in C. – Luchian Grigore Jul 27 '11 at 12:50
  • 1
    @Luchian - the `virtual` keyword and associated compiler restriction does not exist in C, as the others have said. But you can achieve similar behavior in C as described by yi_H and myself. – Eli Iser Jul 27 '11 at 12:53
7

C has no native syntax for virtual methods. However, you can still implement virtual methods by mimicking the way C++ implements virtual methods. C++ stores an additional pointer to the function definition in each class for each virtual method. Thus, you can simply add a function pointer to a struct to simulate virtual methods.

For example

#include <stdio.h>
#include <stdlib.h>

int f2(int x)
{
    printf("%d\n",x);
}

typedef struct mystruct
{
    int (*f)(int);
} mystruct;


int main()
{
    mystruct *s=malloc(sizeof(mystruct));
    s->f=f2;
    s->f(42);
    free(s);
    return 0;
}
Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
  • 3
    +1 Good attempt. But you can't do `int (*f)(int x)=NULL;` in the struct definition itself. – Nawaz Jul 27 '11 at 12:50
  • 1
    I agree with Nawaz - this must be in the definition of the instance (or rely on the compiler to leave uninitialized field 0). Also, you will need to make sure that `s.f` is not `NULL` before calling it. – Eli Iser Jul 27 '11 at 12:57
  • @Eli and Nawaz: Thanks for pointing that out. I updated the code and it now compiles with gcc. – Jack Edmonds Jul 27 '11 at 13:02
5

No you can't. 'virtual' is not part of the C vocabulary, neither is 'access level'

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
Vinicius Kamakura
  • 7,665
  • 1
  • 29
  • 43
  • Indeed the `virtual` keyword is not part of the C language. This doesn't mean object oriented programming is not possible in C. – André Caron Jul 27 '11 at 12:52
  • I agree with you André, but that is besides the point. The OP asked specifically about virtual functions inside structs, in C. – Vinicius Kamakura Jul 27 '11 at 13:03
  • For that matter there are no member functions in C, let alone virtual ones. Function pointers as data members can make the syntax for a call look a little bit like a C++ member function call, of course. – Steve Jessop Jul 27 '11 at 13:12
  • 4
    -1: The lack of a `virtual` reserved word does not imply that you can't have virtual member functions. By that definition, smalltalk does not have polymorphism either. – Sebastian Mach Jul 27 '11 at 13:19
  • 2
    you _can't_ have member functions in C, virtual or not. period. Pointer to functions are, pointer to functions _not_ member functions. Save me the pedantry please. – Vinicius Kamakura Jul 27 '11 at 13:28
  • 3
    @hexa: The point is: Declaring the _lack_ of the keyword `virtual` to be _the reason_ for the lack of member-functions et al. isn't valid. A language's grammar does not need to define `virtual` as a keyword to define runtime-polymorphism or member-functions. Equally, the lack of such production or atom in the grammar does not in itself declare the absence of such functions and behaviour. Therefore not an answer. Therefore -1. period. – Sebastian Mach Jul 27 '11 at 15:08
  • @phresnel I've never even said keyword. I said vocabulary, meaning the concept not the language lexical. I thought that was clear when I also exemplified 'access level', that is not a keyword in C++ either but its part of its vocabulary, its concepts. – Vinicius Kamakura Jul 27 '11 at 15:13
  • @hexa: Then I misunderstood (of course I don't know your knowledge of C++), I thought by "vocabulary", you meant the grammar/language definition (yeah, there's sometimes a correlation between spoken grammars and artificial grammars). But still I think the OPs question is vague enough that naming alternatives is almost mandatory; but not doing so isn't a reason for me to -1, so -1*0. edit: I would remove my downvote, but can't anymore, unless your post is edited :( – Sebastian Mach Jul 27 '11 at 15:20
  • It is all good man, don't worry :) – Vinicius Kamakura Jul 27 '11 at 15:21
  • 1
    I trimmed some excess whitespace and could remove my downvote, I beat the system :) – Sebastian Mach Jul 27 '11 at 15:23
5

You can simulate virtual functions with function pointers. For instance,

struct foo
{
    void(*bar)(struct foo*, int, int);
};

void default_bar ( struct foo * f, int a, int b )
{
    printf("bar(%d,%d)\n", a, b);
}

void setup_foo ( struct foo * f )
{
    f->bar = &default_bar;
}

Then, you can "subclasss" the structure with something like:

struct meh
{
   /* inherit from "class foo". MUST be first. */
   struct foo base;
   int more_data;
};

/* override "method bar". */
struct custom_bar ( struct foo * f, int a, int b )
{
    struct meh * m = (struct meh*)f;
    printf("custom_bar(%d,%d)\n", a, b);
}

void setup_meh ( struct meh * m )
{
    setup_foo(&m->base);
    m->bar = &custom_bar;
}

All of this is labor-intensive and error prone, but it can be done. This type of "inheritance" and "override" implementation is common practice in some well-known C libraries, including jpeglib and libpng. They use this technique to allow you to override the I/O procedures if you're not satisfied with standard C I/O.

Edit: as noted in the comments, some of this code relies on (officially) non-standard behavior that "just happens" to work on most compilers. The main issue is that the code assumes that &m.base == &m (e.g. the offset of the base member is 0). If that is not the case, then the cast in custom_bar() results in undefined behavior. To work around this issue, you can add an extra pointer in struct foo as such:

struct foo
{
    /* same as before ...*/
    /* extra pointer. */
    void * hook;
};

Then, modify the stuff that touches the cast,

void setup_meh ( struct meh * m )
{
    m->base.hook = m;
   /* set up function pointers as usual... */
}

void custom_bar ( struct foo * f, int a, int b )
{
    struct meh * m = (struct meh*)f->hook;
    /* override. */
}

This technique is more reliable, especially if you plan to write the "derived struct" in C++ and use virtual functions. In that case, the offset of the first member is often non-0 as compilers store run-time type information and the class' v-table there.

André Caron
  • 44,541
  • 12
  • 67
  • 125
  • Even though this works, you are relying on compiler extensions for type punning that can lead to undefined behavior blablabla. This works in GCC and MSVC for a fact. Also `void(*bar)(int, int);` should be `void(*bar)(void *, int, int);` – Vinicius Kamakura Jul 27 '11 at 13:07
  • Thanks, indeed the function pointer was declared wrong. Indeed the alignment stuff relies on compiler extensions. You can make it portable using an extra `void*` pointer in `struct foo` that points to the "derived object". However, the technique is sufficiently popular in well-known libraries to be considered "portable". Any compiler that made this type of code break would have lots of complaints from its customers. – André Caron Jul 27 '11 at 13:28
  • @hexa: removed the undefined behavior. See the edit. – André Caron Jul 27 '11 at 13:34
  • Good work, I'd upvote again if I could ;) – Vinicius Kamakura Jul 27 '11 at 13:35
3

You can not. C structs can not have behaviors. They can only have data.

Please see http://www.topcoder.com/tc?module=Static&d1=tutorials&d2=tenBestQuestions for differences between C structs and C++ structs. it is written in the second question.

C++ structures is as different as C++ classes are different from C structs. It's just an analogy.

Plus there's no such thing as inheritence in C. Without inheritence, what would you do with virtual functions?

bliss
  • 330
  • 3
  • 14
  • Question: is a function pointer data or "behavior"? – André Caron Jul 27 '11 at 12:54
  • I don't know much about function pointers but I think that it is a data. After all it is a pointer isn't it? – bliss Jul 27 '11 at 12:59
  • You can sort of do inheritance in C by making the "base" struct the first member of the "child" struct. Then after instantiating the "child" struct, just set its function pointer to the overridden method. – Jack Edmonds Jul 27 '11 at 13:09