Question

I've been mulling this over in my head lately. Most of us are well aware that in C, in order to create a struct, you normally prefix it with a typedef to avoid calling the struct keyword before referencing the object. Of course, C is limited to structs rather than classes. To compensate for this, C tends to use global functions dedicated to a struct to create an object-oriented approach

For example:

typedef struct{
    int foo;
    float bar;
    char* baz;
} SomeStruct;

Vs.

struct AnotherStruct {
    int foo;
    float bar;
    char* baz;
};

AnotherStruct must have the prefix keyword struct before it, when an object of that type is declared within a function. For example:

int main( ... )
{
   struct AnotherStruct obj1; //correct
   SomeStruct obj2; //correct
   struct SomeStruct obj3; //bad
   AnotherStruct obj4; //bad 
}

In terms of the object-oriented approach:

typedef struct {
    //member variables here
} SomeStruct;

SomeStruct* SomeStruct_New( int a, int b, int c )
{
    SomeStruct* obj = calloc( sizeof( SomeStruct ), 1 ); //not sure if that's correct -- been a while since I've used calloc.
    obj.a = a;
    obj.b = b;
    obj.c = c;
    return obj;
}

void SomeStruct_Free( SomeStruct* free )
{
    free( free );
}

These functions are pretty easy to implement without the wrappers - I'm just using them for the sake of example. My point is that, given that you can already create a struct in C++ which doesn't require the typedef to declare without the struct keyword, and using non encapsulated functions which pertained to these structs for an object-oriented approach, I was curious to know if there are any advantages to the C approach of coding in C++, which would include using static global functions as private member functions, along with global function constructors which would return pointers to objects.

This is just mainly out of curiosity, as there are times where I feel like taking the C approach just for the sake of taking it, but this may just be a preferential thing.

Was it helpful?

Solution

It is pretty hard to understand the gist of the question. It seems to me that your main interrogation is whether:

  • "simple" data + functions

is better than

  • objects

in some situations.

No. It's equivalent.

With the exception of exceptions (!) any code that you express in C++ can be expressed in C. It is just a matter of syntactic sugar that make the C++ counterpart easier to read. And before the naysayers jump on the bandwagon, yes virtual tables can be emulated in C.

Still, I would rather use C++. Compiler-checked encapsulation (private), compiler-driven overload selection, compiler-boilerplate (templates). It is just syntactic sugar, but such sweet sugar.

That being said:

class Foo {
  Foo() {}

  friend Foo build(int a, int b);
  friend int getA(Foo const& foo);
  friend int getB(Foo const& foo);

  int a;
  int b;
};

can be thought of as Object Oriented.

EDIT: simple and dummy example of polymorphism.

#include <stdio.h>

// Interface
typedef void (*FunctionPrint)(void const*);

typedef struct {
  FunctionPrint print;
} PrinterInterface;

void print(void const* item, PrinterInterface const* pi) {
  (*pi->print)(item);
}

// Foo
typedef struct { int a; } Foo;

void printFoo(void const* arg) {
  Foo const* foo = (Foo const*)arg;
  printf("Foo{%d}\n", foo->a);
}

PrinterInterface const FooPI = { &printFoo };

// Bar
typedef struct { char* a; } Bar;

void printBar(void const* arg) {
  Bar const* bar = (Bar const*)arg;
  printf("Bar{\"%s\"}\n", bar->a);
}

PrinterInterface const BarPI = { &printBar };

// Main
int main() {
  Foo foo = { 1 };
  Bar bar = { "Hello, World!" };

  print(&foo, &FooPI);
  print(&bar, &BarPI);
}

Result:

Foo{1}
Bar{"Hello, World!"}

OTHER TIPS

As far as I know, such declaration exist just because some common headers (mainly coming form OS APIs: think to windows.h or "xlib.h") have to be used in both C and C++ programs, of unpredictable C and C++ versions.

If such API are rewritten as per today (Note: The API themselves, not just the interface), they will probably not have those kind declarations. Is a sort of "bastard coding" that makes the API developer sure about the memory mapping (important when a struct binds to hardware or external binary formats) and about "magic number definitions", that are never repeated in different headers for different languages.

No I don't think there is any case in C++ where it would make sense.

The most obvious case where you would want to use the C approach is interrupts and thread callback functions. But those can be written as private static members in C++, which is to prefer.

Generally, there are very few cases where it makes sense to even return a pointer from a function in C or C++. Your example isn't good OO, you force the user of your class to use dynamic allocation when there is no need for it. You usually leave allocation to the caller, when writing OO code in C.

I can come up with a few cases in real-time embedded programming when you don't want any constructors to be called and therefore avoid classes entirely, but in such cases you would probably not use C++ at all.

Just recently, I've begun to use Horde3D, that implements (more or less) what you describe. Internally implemented in C++, exposes a simple API in C.

This approach make it attractive for people that, like me, want to reuse the engine by means of a foreign language interface. I'm working on coupling the engine to SWI-Prolog, and since Prolog doesn't follow OOP orientation, there is nothing to gain in using (for instance) OGRE interface. OGRE has more features, but simplicity can have his merits, too...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top