views:

803

answers:

14

As a C++ programmer, we have to deal with concepts and the relation of related concepts before implementing them to classes.

However,how to design a software in procedure languages like C ? How can I deal with concepts without the help of class in C++.

Related:

+8  A: 

In an object-oriented language you get used to thinking of data objects first, then thinking about what methods or behaviors you want to apply to those objects. It helps in procedural programming to think of your data structures separately from the functions that act on them.

Bill the Lizard
+29  A: 

If you are familiar with C++, you might want to consider creating a data struct anywhere you would create a class, and create functions similar to the class methods you might normally create, with the first parameter accepting a pointer to that struct.

John MacIntyre
+1 - just because C doesn't have objects doesn't mean you can't still use object-oriented methods (encapsulation especially) in C. Even polymorphism of sorts is possible. Just look at the use of HANDLE's in the Win32 API.
Eric Petroelje
+1, but I'll say there are significant differences, like having the manually call destructors
Todd Gardner
While learning C++, I realized I should have been doing this all along in C. Leter the Windows API only confirmed this line of thinking. ... thanks for the upvote. ;-)
John MacIntyre
@Todd Gardner-yeah, there are some big paradigm changes. But I think starting with this idea, will keep a lot of complexity in check.
John MacIntyre
You can even put function pointers into your structs to emulate polymorphism. I used that ages ago in a simulation I worked on.
lothar
That crossed my mind when I was first learning C++, but without 'this', is there really any value to doing that? (sincerity intended)
John MacIntyre
Encapsulation is a matter of code organization. Inheritance is more annoying, and I found polymorphism to be a pain. Fortunately, inheritance is overused in C++, and working without it might be useful practice.
David Thornley
@lothar: it's not 'emulating' polymorphism, it's just that you have to provide the infrastructure before using it. OOP languages aren't different beasts, just that they already include a runtime library and syntactic sugar to use it.
Javier
If you are going to do OOP, why bother with C in the first place?
n0rd
@n0rd: there are lots of cases where C is more appropriated than C++; being in those cases shouldn't preclude from using good design, and OOP can be a good design choice. remember OOP, (like structured functional, and many more) is a design style, not a language feature.
Javier
@n0rd, C GUI APIs tend to be written exactly this way. The EFL, GTK+, and several others are implemented as a series of structs with shared members (a sort of pseudo-inheritance), and functions with matching names (like member functions with an explicit "this*").
greyfade
+6  A: 

You might also have a look at Glib/GObject, which provide a class mechanism for the C language. It's used by a lot of projects and it's quite powerful and heavily-tested.

Julien
+2  A: 

Continue to think in terms of classes and the interfaces provided by classes. A C++ class will map to a C struct. The class member functions become regular C functions. Provide a header that declares the external interface to the 'class'. Accept that some parts of C++ are not available in C - namespaces, exceptions (and, of course, classes).

Jonathan Leffler
+6  A: 

It's entirely possible to bring OOP design principles to 'C'. You're missing some of the syntactic sugar, but at the end of the day it's all just structs, functions and pointers.

Take a look at glib, gtk and gts for nice examples of OOP coding style in C.

timday
+6  A: 

Only use Functional Decomposition if the problem you are solving maps well to it.

Remember operating systems, GUI's, and other event driven, non-procedural systems were all written in C long before Objective C and C++ came along. C is not Cobol.

Before learning C++, I wrote an event driven GUI in C utilizing arrays of function pointers. Encapsulation was easy, I made no attempt at polymorphism, some relationships relied on coding standards and naming conventions as namespaces and objects were not available. It incorporated a true parser, recursive as I hadn't taken the Compiler class at Uni yet. And yes, it all fit in 640K, but I did use overlays.

Some people try to cobble up pseudo-objects using function pointers in Structs. I don't see the point.At some point you have to accept the fact you're not using C++.

kmarsh
+2  A: 

With object-oriented languages, such as C++, the problem is broken down into objects, as the name implies. With procedural languages, you want to use functional decomposition, where the problem is broken up into tasks, and each tasks into sub-tasks, and so on, and so on...

Edd
A: 

Here is how you can obtain single inheritance:

struct Base {
 int a;
};    
struct MyStruct {
  Base parent;
  int b;
};

struct MyStruct myStruct;
struct Base *base = (struct Base *) &myStruct;
printf("%d\n", base->a);
aFunctionExpectingBase(base);

This mimics GObject. You can do other tricks they do, for example: in every object-like structure it may be convenient to include a common first-level parent. It could provide basic functionality of your C object system.

+2  A: 

In C, often times programmers will imitate the idea of a class by seperating out related functions into .h/.c files and treating them as a class. Placing variables in local scope can be thought of as 'private'.

byte
A: 

Use Functional Decomposition.

Functional Decomposition is a Top-down method to design a program in a systematic way. The idea is to decompose the problem into it's sub-tasks, decomposing the sub-tasks in turn until the details are fine enough to translate into a programming language. It is up to the designer to choose how to break the problem down.

Rob Kam
Don't downvote this question simply because it doesn't mention OO!
Arafangion
+3  A: 

There's absolutely nothing preventing you from using all the same techniques you use in C++ on C. object oriented design, including multiple inheritance is simple enough to achieve. You can even get template programming done with a little macro cleverness. The only thing is that the resulting C program won't be as elegant as the equivalent C++, because the language doesn't help you with these concepts very much.

There are only really two features the C++ language offers that will be difficult to work around. First is the help C++ offers for template specialization. You will probably have to manage the template object code a bit more carefully than you would with with C++. This is a pretty easy aspect of template metaprogramming in C, though, since getting macros to do the right thing is significantly trickier.

The bigger issue is that the language doesn't automatically finalize class instances when they go out of scope, which is the big C++ concept. You will have to meticulously manage resources in C, where C++ would do all of the work automatically at the right time.

TokenMacGuy
+1 - just to note that the first C++ compilers were actually translators to pure C and they are available even today.
Zyx
+1  A: 

You can mimick C++ class and methods with C struct and function pointers. It is a bit painfull (everything is done behind the scene in C++) but it provides a very good flexibility to your program.

luc
+4  A: 

You have received a lot of proposals how to implement object-oriented concepts in C, but unless the problem domain makes OOP highly desirable (e.g. GUI programming), you should IMO rather use C and other procedural languages in a procedural way. OOP is IMO not inherently better for all scenarios.

You might want to have a look at the "good old" structured analysis method for the analysis/design phase of your project.

ammoQ
+1  A: 

Well, you can still design nice abstract data types in C. You start by typedefing a struct, providing create/destroy functions, and then other setters/getters/doers to operate on that struct:

typedef struct {
  /* maintain private state here */
  unsigned int x;
  char *y;

} mytype_t;

/** Creates a new mytype... */
mytype_t *mytype_create(unsigned int x, char *y);

/** Destroys a mytype, freeing all associated memory. */
void mytype_destroy(mytype_t *t);

/** Does something to mytype... */
void mytype_do_something(mytype_t *t, int bla);

So you implement these functions and maintain your state by accessing the 'private' members in the struct, whose pointer is passed in to each function.

Then you would use this interface like this:

mytype_t* t = mytype_create(foo, bar);
mytype_do_something(t);

/* do some other stuff */

mytype_destroy(t);

The important point is this: as soon as you typedef a struct, users of the type are not allowed to access its members. They should only talk to it via the public interface/functions defined for it.

I see people typedefing structs just to avoid having to type 'struct' all over the place, but you have to think of it as defining a new abstract type, whose internal implementation may change. Sure a user of the type can dive in and access the members but that's a bad thing to do . A typedef struct means "private, keep out!". This is basic information hiding.

I tend to use a prefix style of naming too, i.e. mytype_verb. This helps with intellisense because I can type mytype_ and get a list of functions for that type. It also helps with naming conflicts since there is no namespace support in C, which is why you will see most C libraries use prefixes (like sqlite3_) in front of everything they define.

Mike Weller