How to Implement a Class in C

How do you implement a class in C?

That depends on the exact "object-oriented" feature-set you want to have. If you need stuff like overloading and/or virtual methods, you probably need to include function pointers in structures:

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

float shape_computeArea(const ShapeClass *shape)
{
return shape->computeArea(shape);
}

This would let you implement a class, by "inheriting" the base class, and implementing a suitable function:

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;
}

This of course requires you to also implement a constructor, that makes sure the function pointer is properly set up. Normally you'd dynamically allocate memory for the instance, but you can let the caller do that, too:

void rectangle_new(RectangleClass *rect)
{
rect->width = rect->height = 0.f;
rect->shape.computeArea = rectangle_computeArea;
}

If you want several different constructors, you will have to "decorate" the function names, you can't have more than one rectangle_new() function:

void rectangle_new_with_lengths(RectangleClass *rect, float width, float height)
{
rectangle_new(rect);
rect->width = width;
rect->height = height;
}

Here's a basic example showing usage:

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;
}

I hope this gives you some ideas, at least. For a successful and rich object-oriented framework in C, look into glib's GObject library.

Also note that there's no explicit "class" being modelled above, each object has its own method pointers which is a bit more flexible than you'd typically find in C++. Also, it costs memory. You could get away from that by stuffing the method pointers in a class structure, and invent a way for each object instance to reference a class.

Does C have classes?

No, C doesn't have classes. That said, there are ways of simulating object-oriented programming in C - a quick Google search should yield some useful results.

How are classes implemented internally in C++?

I have not written any c++ compilers, but the structure of a class should contain:

  • base class(es) data part (containing all data for base classes of the class)
  • class instance data part (containing all data for an instance of the class)
  • virtual table pointer (if the class or it's bases have at least one virtual function)

Note: non-virtual functions are referenced statically, so they should not be bound to a class instance directly.

That said, each compiler probably implements this a bit differently.

TLDR: essentially yes, the implementation has to be similar to the class hack (but this should be transparent/irrelevant for developers).

Edit:

This post is mostly speculation, based on years of debugging with visual studio (very subjective), backed with some experience years ago, maintaining a project that had the class hack supporting inheritance, implemented in C (such experience is very subjective as well).

For an example, in Visual Studio 6, you could see that the virtual function table was allocated before the c++ implementation-specific data. That is, a class looked like this:

[vtbl][data]
^1 ^2

so if this was for (for example) struct X { virtual ~X(); int i; }, then writing:

X a;
X *p = &a;

would create something similar to this:

[ptr + 1] -> any other virtual functions
[ptr + 0] -> X::~X
^x

[^x][data]
^1 ^2
^p = ^2;

with ^1 being where the operating system would allocate memory (and the vtbl would be filled in within the implementation of new), then the offset to user data (vtbl + sizeof (vtbl)) would be returned to the client code, as the address of the class. I don't know if this is still the case.

What is the equivalent of class in pure C

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 PyIntObjects and PyDictObjects 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.

Emulating Classes in C using Structs

You would do much better to implement it as follows:

#include <stdio.h>

struct point {
float x;
float y;
};

void point_setCoordinates(struct point *self, float x, float y){
self->x = x;
self->y = y;
}

float point_getXCoordinate(struct point *self){
return self->x;
}

float point_getYCoordinate(struct point *self){
return self->y;
}

int main(void) {
struct point my_point;

point_setCoordinates(&my_point, 1, 2);

printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(&my_point),
point_getYCoordinate(&my_point));

return 0;
}

A few things to note:

  • As @Olaf has pointed out, never typedef a pointer - it hides your intent and makes things unclear. Yes, it's all over poor APIs (e.g: Windows), but it reduces readability.
  • You really don't need these functions to be the equivalent to virtual functions... just have a set of point_*() functions that you call on the point 'thing'.
  • Don't confuse things with poor names... if it's an X,Y point, then call it such - not an object (which is a very generic concept).
  • You need to call functions... in your call to printf() you used point.getXCoordinate - that is to say you took it's address and asked printf() to display it as though it were a float
  • You might start to wonder why you'd care about calling a function to get access to a variable that is inside a transparent struct... See below.

Many libraries / APIs provide opaque datatypes. This means that you can get a 'handle' to a 'thing'... but you have no idea what's being stored within the 'thing'. The library then provides you with access functions, as shown below. This is how I'd advise you approach the situation.

Don't forget to free the memory!

I've implemented an example below.

point.h

#ifndef POINT_H
#define POINT_H

struct point;

struct point *point_alloc(void);
void point_free(struct point *self);

void point_setCoordinates(struct point *self, float x, float y);
float point_getXCoordinate(struct point *self);
float point_getYCoordinate(struct point *self);

#endif /* POINT_H */

point.c

#include <stdlib.h>
#include <string.h>

#include "point.h"

struct point {
float x;
float y;
};

struct point *point_alloc(void) {
struct point *point;

point = malloc(sizeof(*point));
if (point == NULL) {
return NULL;
}

memset(point, 0, sizeof(*point));

return point;
}

void point_setCoordinates(struct point *self, float x, float y) {
self->x = x;
self->y = y;
}

float point_getXCoordinate(struct point *self) {
return self->x;
}

float point_getYCoordinate(struct point *self) {
return self->y;
}

void point_free(struct point *self) {
free(self);
}

main.c

#include <stdio.h>

#include "point.h"

int main(void) {
struct point *point;

point = point_alloc();

point_setCoordinates(point, 1, 2);

printf("Coordinates: X Coordinate: %f, Y Coordinate: %f\n",
point_getXCoordinate(point),
point_getYCoordinate(point));

point_free(point);

return 0;
}

Creating and Implementing Classes in C++

In your header use:

#include<string>

How to use c++ objects in c?

Give the C++ module a C interface:

magic.hpp:

struct Magic
{
Magic(char const *, int);
double work(int, int);
};

magic.cpp: (Implement Magic.)

magic_interface.h:

struct Magic;

#ifdef __cplusplus
extern "C" {
#endif

typedef Magic * MHandle;
MHandle create_magic(char const *, int);
void free_magic(MHandle);
double work_magic(MHandle, int, int);

#ifdef __cplusplus
}
#endif

magic_interface.cpp:

#include "magic_interface.h"
#include "magic.hpp"

extern "C"
{
MHandle create_magic(char const * s, int n) { return new Magic(s, n); }
void free_magic(MHandle p) { delete p; }
double work_magic(MHandle p, int a, int b) { return p->work(a, b); }
}

Now a C program can #include "magic_interface.h" and use the code:

MHandle h = create_magic("Hello", 5);
double d = work_magic(h, 17, 29);
free_magic(h);

(You might even want to define MHandle as void * and add casts everywhere so as to avoid declaring struct Magic in the C header at all.)

How to implement static classes in c++?

C++ does not have "static classes" as they formally exist in other languages. You can, however, delete the default constructor (C++ >= 11) or make it private and unimplemented (C++ < 11) which has the same effect of making the type not constructible:

// C++ >= 11
class Math
{
public:
Math() = delete;
};

// C++ < 11
class Math
{
private:
Math(); // leave unimplemented
};

With this code, the line Math m; will fail:

(C++ >= 11) error: use of deleted function 'Math::Math()'

(C++ < 11) error: 'Math::Math()' is private within this context

However, "static classes" are mostly an anti-pattern in C++ and free functions should be preferred. (There are some cases where static classes can be useful, particularly when doing template metaprogramming. If you're not doing that then you almost certainly don't need a static class.)

Consider instead declaring the functions in a namespace:

namespace math {
int pow(int, int);
}

How to create a C class on Eclipse

C does not have classes.

The capability of your IDE to compiler both C and C++ doesn't mean that it can transfer the constructs and concepts of C++ into a C program. It means that you can either compile a C program, or a C++ one.



Related Topics



Leave a reply



Submit