Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » C with structs or C++ with classes... Your choice and why.

This thread is locked; no one can reply to it. rss feed Print
C with structs or C++ with classes... Your choice and why.
David_at_wedu
Member #7,407
June 2006

I'll admit that I am new to C/C++ programming. I've been doing my studies via online resources and a few different game programming specific books. The one that I'm currently reading presents its code strictly in C. The best example I can give is that the objects the character controls are defined as structs(). The initial book I read however, was C++ all the way, so it talked of using classes and objects.

I guess my question is are there any advantages to using one over the other?

Again, I apologize for my newbie-ness... Just looking to get off on the right foot. :)

ReyBrujo
Moderator
January 2001
avatar

It depends. C++ is a superset of C, so anything you would do in C you can do in C++. Of course, a good design usually divides the program in objects. For big programs, a class structure really helps. You can easily implement a lot of design patterns in C++ that will make the code better maintainable(sp?) and easily expandible(sp?).

--
RB
光子「あたしただ…奪う側に回ろうと思っただけよ」
Mitsuko's last words, Battle Royale

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

I guess my question is are there any advantages to using one over the other?

None. Just depends which interface you prefer working with.

Someone may be able to come up with some obscure programming feature the C++ way makes easier, but I'm too lazy.

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Steve++
Member #1,816
January 2002

The good thing about structs is that you can bundle related variables into one stucture. These variables are related usually by some object they are modelling. Classes are just an evolution of that, taking it one step further by bundling the procedures that manipulate those variables with the variables themselves. This makes life much easier.

The only real pitfall in choosing C++ over C is that C++ has so many more tricks that you can make it do. This may seem like a good thing, but soon you find yourself spending too much time trying to make C++ do all its nice tricks when all you really wanted it for was C programming with classes. I tend to use C++ just for its ability to use classes. I don't personally overload operators, but I'll happily use classes (such as the D3DX family) that use this feature effectively. I use templates for parameterised classes, but not for any ugly metaprogramming tricks. I avoid multiple inheritence like the plague. The exception is that I sometimes make purely abstract classes and use them like Java interfaces, which can use multiple inheritence.

So my answer would be to use subset of C++ that extends C as far as you want it to and no further.

Krzysztof Kluczek
Member #4,191
January 2004
avatar

Quote:

Of course, a good design usually divides the program in objects. For big programs, a class structure really helps.

This, and on top of it: less typing and more readable code, at least for me.

Using functions:

struct tEnemy {
  int x,y;
};

void enemy_follow_player(tEnemy *e,int px,int py)
{
  e->x += MID(-1,px - e->x,1);
  e->y += MID(-1,py - e->y,1);
}

Using methods:

struct tEnemy {
  int x,y;

  void follow_player(int px,int py);
};

void tEnemy::follow_player(int px,int py)
{
  x += MID(-1,px - x,1);
  y += MID(-1,py - y,1);
}

Basically, you've just saved some "e->"'s. Also calling it is IMHO more readable:

enemy_follow_player(enemy,px,py);  // function
enemy->follow_player(px,py);       // method

A J
Member #3,025
December 2002
avatar

C++ structs are classes that default to private scope.

C++ can be alot safer than C, as long as you know what your doing.

___________________________
The more you talk, the more AJ is right. - ML

_Dante
Member #7,398
June 2006
avatar

Quote:

C makes it easy to shoot yourself in the foot. C++ makes it harder, but when you do, you blow off your whole leg.

Bjarne Stroustrup

-----------------------------
Anatidaephobia: The fear that somehow, somewhere, a duck is watching you

Audric
Member #907
January 2001

It's probably THE most tricky question one could ever ask :)
I'd say, when you encounter a case that resembles something you saw in C++, try the C++ method.

Any time you're going to dynamically allocate and free stuff, C++ classes would probably be safer (there are less different ways to do something wrong)

One case where you'll be happy to use C structs is whenever you want to put constant data in the source itself:

typedef struct {
   char * name;
   int level;
   int hp;
   int xp_reward;
} S_ENEMY;

S_ENEMY enemy_table[] = {
{ "goblin", 1, 15, 100 },
{ "dragon", 10, 200, 1000},
{ NULL, 0, 0, 0 } };

Array size computed at compile time, data automatically initialized before main().
It's almost impossible to go wrong there :)

thematrixeatsyou
Member #6,183
September 2005
avatar

You forgot the other option: Assembler. This is by far the easiest language to do OOP in. Not the easiest language at all, but you can do something like THIS(16-bit x86 ASM):

1mov bx,StartPointers
2mov cx,[CountPointers]
3LoopStart:
4push bx
5push cx
6push cs
7mov ax,ReStartPos
8push ax
9mov ax,[bx]
10push ax
11mov ax,[bx+2]
12push ax
13mov dx,[bx+4]
14retf
15ReStartPos:
16pop cx
17pop bx
18add bx,0006h
19loop LoopStart

Then again, ASM is bloody hard for a first-time programmer. But if you can code ASM, you can make SURE it does what it's supposed to. But if you can do OOP in C, then you've officially mastered the core aspects of C. C++ is lazy, as miran was with the AMGC2, which only supports C++, and not a standard DLL.

But really, who NEEDS classes?

typedef struct {
  int x,y;
  BITMAP *sprite;
} Noob;

void followplayer(Noob *n,int ex,int ey){
  n->x+=(ex<px?1:-1);
  n->y+=(ey<py?1:-1);
}

(that (ex<px ? 1 : -1) is (if_this_is_true ? give_this : else_give_this))

But it's your own personal preference. I prefer C because it's simpler, and you can ignore all that "using namespace std" crap. If you are really good at JavaScript, take C.

I think the C++ programmers are trying to persuade you to take C++.

More readable code? What a load of crap. They're virtually the same for readability.

good food is t3h pwn <-- if anyone can find out how old this sig is they win an ascii penguin

_Dante
Member #7,398
June 2006
avatar

Quote:

I think the C++ programmers are trying to persuade you to take C++.

You say that as though it's different from a C programmer trying to persuade him to take C...

Quote:

But if you can do OOP in C,

Stop right there. You can't do OOP in C, not really. C has limited inheritance, even more limited encapsulation and no polymorphism. OOP is more than just classes, and C doesn't even have that.

-----------------------------
Anatidaephobia: The fear that somehow, somewhere, a duck is watching you

Kitty Cat
Member #2,815
October 2002
avatar

Quote:

You can't do OOP in C, not really

OOP is a programming methodology, not a language-specific feature. You can very well do OOP in C. Allegro is an example of this.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Audric
Member #907
January 2001

Only wanted to restate...

David_at_wedu said:

C with structs or C++ with classes (...) are there any advantages to using one over the other?

now one answer to thematrixeatsyou:

Quote:

More readable code? What a load of crap. They're virtually the same for readability.

I don't agree. Being able to refer it "itself" by typing "x, y, hp" instead of "p->x, p->y, p->hp" may seem petty, but in my game it spared me about 200 times typing the "p->", just for the player and one missile. By the time the game is finished, it'll be 1500 times. That's a net benefit to me.

David_at_wedu
Member #7,407
June 2006

Wow, I didn't expect to get so much input. Thanks everyone...

Quote:

It depends. C++ is a superset of C, so anything you would do in C you can do in C++. Of course, a good design usually divides the program in objects. For big programs, a class structure really helps. You can easily implement a lot of design patterns in C++ that will make the code better maintainable(sp?) and easily expandible(sp?).

That's the impression I was getting, based off just sort of comparing code from the C-centric book and thinking, "how would this be setup with OOP." I really want to think as progressively as possible in my coding, and while I know C++ is based on C, C++ is more or less the standard coding language for games these days.

Quote:

The only real pitfall in choosing C++ over C is that C++ has so many more tricks that you can make it do. This may seem like a good thing, but soon you find yourself spending too much time trying to make C++ do all its nice tricks when all you really wanted it for was C programming with classes.

I get what you're saying. I'm well aware that my C++ know-how is probably less than 10% of what I can actually do with the language. I've been doing my best to step into the deep-end slowly instead of just diving headlong. :)

Quote:

I don't agree. Being able to refer it "itself" by typing "x, y, hp" instead of "p->x, p->y, p->hp" may seem petty, but in my game it spared me about 200 times typing the "p->", just for the player and one missile. By the time the game is finished, it'll be 1500 times. That's a net benefit to me.

This may be true, but I can also see the other side of the argument. For example, the C-centric book I mentioned defines its two player objects as structs like this:

players[num].x - X position
players[num].y - Y position
players[num].score - Score
players[num].dir - Direction

In this instance, num is an int that defines either player one -- index 0 -- or player two -- index 1. While it makes perfect sense to me, I abhored having to write "players[num]" five hundred times when changing or checking attributes. It'd be so much simpler to do with C++:

player1->x
player2->y
etc. etc.

I definitely see both sides of this. I find myself leaning towards C++, if only to stay progressive, but I do really appreciate everyone's input on this topic. ;D

Onewing
Member #6,152
August 2005
avatar

Quote:

Wow, I didn't expect to get so much input. Thanks everyone...

Welcome to Allegro.cc!

Quote:

definitely see both sides of this. I find myself leaning towards C++

They don't call it C/C++ for nothing. You're better off knowing both (which shouldn't be that hard once you get one down) and using whatever fits the task at the time IMHO.

[EDIT]
Most game-wise stuff, I like more C++ standards. It's more modular and easy to construct a sensible design, which is why I think it is typically used for today's games. However, in the business world, C is still commonly used (basically, all that class stuff just isn't needed for what they want).

I just found out I can use C modules with Informix 4gl (which is what I do at work) and I'm ecstatic even though I prefer C++. ;)

------------
Solo-Games.org | My Tech Blog: The Digital Helm

_Dante
Member #7,398
June 2006
avatar

Quote:

OOP is a programming methodology, not a language-specific feature. You can very well do OOP in C. Allegro is an example of this.

I never said it was a language-specific feature, I said C wasn't fully capable of it, and it isn't. Allegro takes an object oriented approach, certainly, but it falls a little short. Look it up in any text you like; "real" OOP requires encapsulation, inheritance, and polymorphism. C can approximate these, but only to a certain degree. OOP requires certain language features, and C doesn't have them.

[EDIT]
Lest people start jumping all over me with arguments about why C is better, notice that I'm not taking a stance either way, I'm simply pointing out the fact that C++ has some features that C does not. That, in and of itself, does not constitute an argument that one is better than the other, it's just statement of fact. Arguing that C is OOP doesn't make it so.

Now, I'm the president of "C++ has too many features", but in the end it doesn't really matter, because it still adheres to the spirit of C that says, "if you don't want it, don't use it". I prefer C++ because it gives me the features I want, and doesn't force me to use the ones I don't (for the most part).

-----------------------------
Anatidaephobia: The fear that somehow, somewhere, a duck is watching you

23yrold3yrold
Member #1,134
March 2001
avatar

Quote:

Welcome to a C vs. C++ thread!

Fixed.

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Paul Pridham
Member #250
April 2000
avatar

Quote:

players[num].x - X position
players[num].y - Y position
players[num].score - Score
players[num].dir - Direction

In this instance, num is an int that defines either player one -- index 0 -- or player two -- index 1. While it makes perfect sense to me, I abhored having to write "players[num]" five hundred times when changing or checking attributes. It'd be so much simpler to do with C++:

player1->x
player2->y
etc. etc.

Note that the code you posted above is 100% C, in both cases. :) There's no reason to use an array to access objects in C if you don't want to. C is perfectly capable of accessing said objects through pointers, as described in the second part of your example. I do this quite a lot in my C code.

_Dante: C is perfectly capable of all of the OOP features that you describe. Approximation? The resulting code may not look like what you'd see in C++, but the functionality is similar if not identical. I've successfully encapsulated, templated, polymorphed, and inherited using C. As well, certain things like prototyped OO, which is not supported in C++ directly, are just as easily accomplished in C as the rest of the OO features. My final advocacy for the C way of doing things is freedom. :) Many things that are frowned upon in C++ land are perfectly acceptable and embraced in C. If you want to be rigidly restricted to a certain way of thinking, spend a lot of time designing the perfect class hierarchy, then embrace the C++ OO methodology. If, like me, you'd rather dispense with the handcuffs and pedantic fluff that gets in the way of actually creating a game, then try the C way. :P ;)

Andrei Ellman
Member #3,434
April 2003

_Dante said:

Quote:

But if you can do OOP in C,

Stop right there. You can't do OOP in C

Oh yes you can. Doing OOP in C does not require the usage of all of C++'s features in C. However, while OOP is possible in C, it can be a bit tedious at times. I'm currently working on a C program that I started some time ago, and I'm gradually making it more and more C++ like by using an OOP design.

The example that Krzysztof posted is how you would emulate objects (combining methods and data) in C. To make it clearer to read and see which is the object being worked on, you could call the pointer to the object some variation on 'this' (I use Hungarian notation), so 'This' becomes 'epThis' (I've only bothered with turning 'epThis' into Hungarian notation), the code becomes...

struct tEnemy {
  int x,y;
};

void enemy_follow_player(tEnemy *epThis,int px,int py)
{
  epThis->x += MID(-1,px - epThis->x,1);
  epThis->y += MID(-1,py - epThis->y,1);
}

It is possible to go further in C. Inheritance can be emulated in C too. Immagine if the enemy has multiple behaviour patterns depending on it's state. Just include a function pointer in the struct, and change this function pointer depending on the state.

1typedef void(TtBehaviourFunction)(tEnemy *epThis, int px, int py); /*!< Shortcut for a function-pointer to an enemy-behavour function */
2 
3struct tEnemy {
4 int x,y;
5 TtBehaviourFunction *fpBehaviour;
6};
7 
8void enemy_follow_player(tEnemy *epThis,int px,int py)
9{
10 epThis->x += MID(-1,px - epThis->x,1);
11 epThis->y += MID(-1,py - epThis->y,1);
12}
13 
14void enemy_avoid_player(tEnemy *epThis,int px,int py)
15{
16 epThis->x -= MID(-1,px - epThis->x,1);
17 epThis->y -= MID(-1,py - epThis->y,1);
18}
19 
20void enemy_setup(tEnemy *epThis)
21{
22 /* ... */
23 epThis->fpBehaviour = enemy_follow_player(); /* This is the initial enemy-behaviour - change according to state */
24}
25 
26 
27void do_logic()
28{
29 epEnemy->fpBehaviour(epEnemy, px, py); /* Do the enemy's behaviour method */
30 
31 if(state_changed())
32 {
33 if(state==foo)
34 {
35 epEnemy->fpBehaviour = enemy_avoid_player; /* Change the behaviour of the player */
36 }
37 else if(state==bar)
38 {
39 epEnemy->fpBehaviour = enemy_follow_player; /* Change the behaviour of the player */
40 }
41 }
42 
43 
44}

Here, it is as if fpBehaviour is a virtual function. Just set it to point to a method for dealing with player behaviour. If you have several methods that change at once, changing all these methods can be a bit time consuming, so what we do is to use a structure called a vtable. This is a structure of function pointers that are associated with a particular state. So if the state changes, instead of changing a whole bunch of function-pointers, just change the vtable. An example...

1typedef void(TtBehaviourFunction)(tEnemy *epThis, int px, int py);
2typedef void(TtAnotherBehaviourFunction)(tEnemy *epThis, int foo);
3typedef int(TtStateGettingFunction)(tEnemy *epThis);
4 
5struct tEnemyBehaviourVtable
6{
7 TtBehaviourFunction *fpBF1;
8 TtBehaviourFunction *fpBF2;
9 TtAnotherBehaviourFunction *fpABF;
10 TtStateGettingFunction *fpSGF;
11};
12 
13tEnemyBehaviourVtable vtBehaviourVT1 =
14{
15 enemy_follow_player,
16 enemy_follow_player_quickly,
17 enemy_make_noise,
18 enemy_get_aggression,
19}
20 
21tEnemyBehaviourVtable vtBehaviourVT2 =
22{
23 enemy_avoid_player,
24 enemy_avoid_player_quickly,
25 enemy_make_squeak,
26 enemy_get_fear,
27}
28 
29struct tEnemy {
30 int x,y;
31 tEnemyBehaviourVtable *vtpBehaviour;
32};
33 
34 
35void enemy_setup(tEnemy *epThis)
36{
37 /* ... */
38 epThis->vtpBehaviour = vtBehaviourVT1; /* This is the initial enemy-behaviour - change according to state */
39}
40 
41 
42void do_logic()
43{
44 epEnemy->vtpBehaviour->fpBF1(epEnemy, px, py); /* Do one of the enemy's methods */
45 epEnemy->vtpBehaviour->fpABF(epEnemy, nFoobar); /* Do another one of the enemy's methods */
46 
47 if(state_changed())
48 {
49 if(state==foo)
50 {
51 epEnemy->vtpBehaviour = vtBehaviourVT1; /* Change the behaviour of the player */
52 }
53 else if(state==bar)
54 {
55 epEnemy->vtpBehaviour = vtBehaviourVT2; /* Change the behaviour of the player */
56 }
57 }
58 
59}

While a vtable only involves changing a single pointer instead of a set of pointers, it also means the code has to make an extra dereference.

So in answer to the original question "C with structs or C++ with classes... Your choice and why.", I'd say "Whatever you feel the most comfortable with". But saying that, I'd encourage programmers to experiment with new programming paradigms from time to time - OOP being one of them.

AE.

--
Don't let the illegitimates turn you into carbon.

A J
Member #3,025
December 2002
avatar

Apples and Oranges.

___________________________
The more you talk, the more AJ is right. - ML

_Dante
Member #7,398
June 2006
avatar

I'm well aware of how to emulate objects in C and do most of what everybody has pointed out here. I would still argue that everything posted to this point still "approximates" polymorphism and encapsulation. Calling a particular function in a switch statement isn't polymorphism, it's essentially an if-else construction. The true power of polymorphism comes from the parent class needing absolutely no knowledge of the child class, other than the fact that it inherits a virtual method from the parent. So calling something like;

object->doSomething();

will always result in the correct behaviour, and I didn't have to touch the parent class or the calling code to accomplish it.

True encapsulation requires information hiding, and C is not capable of this. If there's a member in your C "class", I can access it if I can find it (and with most modern IDEs, I can most certainly find it).

If you don't agree with all of that (or I'm simply out-and-out wrong), my final argument as to the superiority of C++ over C in an OO context, it does make all of this much easier. You're given a this pointer, v-tables, quick & easy inheritance, encapsulation, etc, etc. Why re-invent the wheel?

Lastly, to Paul Pridham: C++ offers the same freedom that C does. C++ is a superset of C - anything C can do, C++ can do. Admittedly, you need an extra cast here and there because the compilers are more strict, but as I mentioned before, C++ gives me the features I want, and allows me to ignore the ones I don't. Simply because something is frowned upon by a particular group, doesn't mean it's prohibited by the language. Nobody's holding a gun to anybody's head to "design the perfect class hierarchy" (except maybe Grady Booch).

-----------------------------
Anatidaephobia: The fear that somehow, somewhere, a duck is watching you

Steve++
Member #1,816
January 2002

If you find yourself making C do C++ things, then perhaps it's easier to use C++. You can still use C withing C++, so you lose nothing by doing this.

As far as C giving more freedom, that's a complete fallacy. The truth is the C++ gives compiler warnings potentially where C doesn't, but it compiles the code anyway. For example, C will happily let you implicitly convert a float to an int, potentially losing precision. C++ will warn you about this possible loss in precision, but will let you do it anyway. An explicit cast will turn off this warning and show readers of the code that a conversion is taking place.

However, if C++ was actually being restrictive, that would only be a good thing. Freedom in programming languages gets you into trouble. The right amount of restriction actually increases productivity and expressivity because you know there are certain errors that you cannot make in some more restrictive languages that you can make in some less restrictive languages.

Quote:

I get what you're saying. I'm well aware that my C++ know-how is probably less than 10% of what I can actually do with the language. I've been doing my best to step into the deep-end slowly instead of just diving headlong. :)

My C++ know-how is probably within the 10-25% range. That, combined with my ~85% C knowledge is more than enough for me to be productive in C++. There's no need to learn more. The design philosophy behind C++ is that it's a better C. That's precisely how I use it.

Jonny Cook
Member #4,055
November 2003

Quote:

But if you can do OOP in C, then you've officially mastered the core aspects of C. C++ is lazy, as miran was with the AMGC2, which only supports C++, and not a standard DLL.

That's a great philosophy you've got there. ::) "Always do it the hard way!" C isn't an object oriented language, therefore object oriented programming is not one of it's core aspects. If you design your code to be object oriented that's great, but what's the point of taking a system that was designed to be used one way, and forcing it to do something else? In Allegro's case it's fine, since it's oriented toward a wider audience. But there is nothing lazy about using your tools they way they are intended to be used, especially when your job is to make something quickly that's both fast and efficient.

Quote:

I prefer C because it's simpler, and you can ignore all that "using namespace std" crap.

It looks like you are the lazy one here.

Quote:

You forgot the other option: Assembler. This is by far the easiest language to do OOP in. Not the easiest language at all, but you can do something like THIS(16-bit x86 ASM):

Is it really? I honestly doesn't see how it could be. I personally don't know how to program in it, but I've read quite a bit on the topic and I know enough to question the validity statement. I don't quit know what the code you posted accomplishes, but it certainly doesn't look like it does anything amazing.

The face of a child can say it all, especially the mouth part of the face.

Richard Phipps
Member #1,632
November 2001
avatar

Although you can program in C++ in the same manner as C, there is often a difference in programming approaches (procedural v Object Orientated). This is the biggest difference for me (and the hardest to adapt to).

Jonny Cook
Member #4,055
November 2003

To me it seems like the C++ approach is more complicated only if you are coming at it from a C point of view. Good OO code should be simple and straightforward. It should explain itself. However, I often find myself going way overboard with it, i.e., using all the C++ features I can in hopes that it will make my code more robust. It usually ends up like a big bowl of spaghetti code, exactly what OO code isn't supposed to be.

The face of a child can say it all, especially the mouth part of the face.

GullRaDriel
Member #3,861
September 2003
avatar

Object is a matter of how you mind your code. The language is a plus, but if you are thinking OOP, you code OOP. You can't say that because the way of coding is different it can not be OOP. It is just that your mind is too close for accepting the fact. You can code in what you want, the processor just have a limited couple of instructions.

Some can prefer C, other C++,pascal,basic,C#... I personally prefer C. And so ? You can not live knowing that other don't use the same tool than you ? Héhé.

I love those fights. The result is always the same, but I love.

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!



Go to: