In OOP languages, we have classes. Is there an equivalent to class in pure C?
-
2There are none. Class-like functionality can be *emulated* through different means, but there are no equivalents. – Some programmer dude Apr 06 '16 at 07:09
-
I can only think of structs ... – mvidovic Apr 06 '16 at 07:10
-
4Possible duplicate of [How do you implement a class in C?](http://stackoverflow.com/questions/1403890/how-do-you-implement-a-class-in-c) – Schafwolle Apr 06 '16 at 07:57
-
2The OO definition of a class is something like: an autonomous object which doesn't depend on the outside world, but is only concerned with it's own designated task. The class hides part of the implementation that aren't relevant to the caller through private encapsulation of data and functions. A class can get inherited. Given this definition, C has classes and can be used for OO programming. It does not have a class keyword, however. Note that there is no such thing as "object-oriented languages". There are only languages with or without built-in support for object-oriented features. – Lundin Apr 06 '16 at 08:55
3 Answers
There is none. This fact was the original motivation for the development of C++, back when C++ was called "C with Classes". The closest thing you can get is a struct
.
There is a feature in C intended to facilitate a sort of pseudo-inheritance, but it doesn't come close to an actual object-oriented class system. A pointer to a struct can legally be cast to and from a pointer to the struct's first member, so you can sort of "extend" a struct type A by having another struct type B start with a member of type A.
For example, you can have a PyObject
struct type and a bunch of struct types that all start with a PyObject
member, say PyIntObject
, PyDictObject
, etc:
typedef struct {
...
} PyObject;
typedef struct {
PyObject ob_base;
// more members...
} PyIntObject;
typedef struct {
PyObject ob_base;
// more members...
} PyDictObject;
You could then pass PyIntObject
s and PyDictObject
s around with PyObject
pointers and use the data in the PyObject
part to tell what the type of the enclosing struct is.
As you may have guessed from the names, I've taken this example from Python, where this mechanism is used to implement Python's object-oriented type system on top of C.

- 260,549
- 28
- 431
- 505
-
Somebody seems to have just switched their upvote to a downvote. Any particular reason? Some issue with the lengthy Python example, perhaps? – user2357112 Apr 06 '16 at 07:30
There is nothing equivalent to classes
. Its a totally different paradigm. You can use structures
in C. Have to code accordingly to make structures do the job.

- 1,487
- 1
- 16
- 27
You can swap "Class" in C++ for "struct".
I'm not saying you should but one mans object is another mans struct with some functions that operate on that struct and where the first parameter to the function is the struct itself. Obviously C++ adds some extra bits. C and opaque pointers are also Objects
and very useful ones at that.
#include <iostream>
struct Cat {
public:
Cat(int initialAge); // constructor
~Cat(); // destructor
int GetAge();
private: // begin private section
int itsAge; // member variable
};
Cat::Cat(int initialAge) {
itsAge = initialAge;
}
int Cat::GetAge() {
return itsAge;
}
int main(void) {
Cat *cat = new Cat(1);
std::cout << "This cat declared as a struct is " << cat->GetAge() << " years old" <<std::endl;
return 1;
}
You can achieve a similar thing in C with a bit more work... Header file is
#ifndef CAT_H
#define CAT_H
#include <stdlib.h>
#include <stdio.h>
typedef struct Cat Cat;
typedef struct CatOps {
int (* GetAge )();
} CatOps;
struct Cat {
void * obj;
CatOps * ops;
};
Cat * new_cat(int age);
void delete_cat(Cat * cat);
#endif /* CAT_H */
.c file is
#include "cat.h"
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
typedef struct cat_obj {
int age;
} cat_obj;
int get_age();
static CatOps CAT_OPS = {
.GetAge = get_age,
};
Cat * new_cat(int age) {
Cat * imp;
cat_obj * obj;
imp = malloc(sizeof(*imp));
obj = malloc(sizeof(*obj));
imp->obj = obj;
imp->ops = &CAT_OPS;
return (Cat*)imp;
}
void delete_cat(Cat *cat) {
free(cat->obj);
free(cat);
}
static void get_age(Cat *cat) {
cat_obj *c = (cat_obj*)cat->obj;
}
Note, I've not tested it but if you know C/C++ you should recognize the idiom.

- 11,298
- 1
- 29
- 43
-
1Nice example. For better type safety you could replace the `void * obj;` with a pointer to incomplete type. That is, in the header add `typedef struct cat_obj cat_obj;`, and change the struct `struct Cat { cat_obj * obj;`, The `cat_obj` will still have full private encapsulation. CatOps * ops; };`. – Lundin Apr 06 '16 at 08:49
-
That would mean I wouldn't be able to change the object in the `.c` file without aliasing it or `cat_obj` would need to be a union of types. – Harry Apr 06 '16 at 16:35
-
You shouldn't change the object type, it always points to a `cat_obj`. So if `Cat` is inherited by `FluffyCat`, then the constructor in `FluffyCat` would use a completely new definition of the private data. Usually I solve such things by creating a second header file. `cat.h` remains the user interface with the incomplete type declaration of `cat_obj`, and `cat_inherit.h` is a private header not available to the caller, containing the type definition. Then `fluffy_cat.c` can include `cat_inherit.h` and create its own typedef, containing one `cat_obj` and one `fluff_obj`. – Lundin Apr 07 '16 at 06:52
-
@Lundin I'd like to see an example of what you're doing. I'm probably misunderstanding something but it looks like you're aliasing things, if not then an example would help, these comments suck for anything remotely complicated. – Harry Apr 07 '16 at 07:01