Sign in to follow this  
__SKYe

Coding Style Help

Recommended Posts

First of all, good day gentlemen.

Although the tile says coding style, my problem isn't really with whitespace, commenting, variable notation or any such thing.
I'll try to explain:

Imagine i have a class for data management (responsible for holding sounds, images, etc). Then i make a class that displays some graphics on the screen, and another that plays a sound. Both these classes need data from the data management class, so how would i do this (this does not extends just to classes, but variables in general)?

Should i make the data management class global, and access it in the audio and graphics class like a global var? Or should a define the data class inside the program as a private var, and pass it in the functions that display the graphics and plays the sound, every time i want to do so?

It's not that i can't make it work, but i'd like to have your opinions on how should i do it, to establish some kind of standard in my programming, (another example, should i defined the variables i need inside the main, and pass them along to any function that needs them?).

So, i'd really appreciate any answers, and if possible, to know how you do it in your projects/programs.

Thanks in advance.

Share this post


Link to post
Share on other sites
[quote name='3333360' timestamp='1335003059' post='4933484']
First of all, good day gentlemen.
[/quote]
There are some ladies round these parts too, but good day all the same :)

[quote]
Imagine i have a class for data management (responsible for holding sounds, images, etc). Then i make a class that displays some graphics on the screen, and another that plays a sound. Both these classes need data from the data management class, so how would i do this (this does not extends just to classes, but variables in general)?
[/quote]
Pass arguments and use interfaces to decouple components sensibly.

Unfortunately, what 'sensibly' means might only become apparent after a lot of practice, making your own mistakes and learning from them. On the other hand, I suspect it's the case that the average person learns faster from making mistakes, as opposed to trying to follow advice laid out by books and people on the internet. I think it's almost invariably true that the second time you (re)write a piece of code, it will come out better, irrespective of how much experience you have. So don't be afraid to just try stuff and try stuff again.

[quote]
Should i make the data management class global, and access it in the audio and graphics class like a global var?
[/quote]
Globals have their uses, but in general avoid them wherever it's not too inconvenient to do so. This advice stems from the 'fact' that you want any side effects in your code to be obvious from a casual reading. Using interfaces carefully should reduce the amount of global data you need.

And actually, "data management classes" [i]typically[/i] shouldn't be anything more complicated than your language's built-in containers (e.g. std::vector<>, std::map<>, etc in C++), or lightweight wrappers around them. Don't make things more complicated than they need to be until you know there will be an actual benefit.

[quote]
Or should a define the data class inside the program as a private var, and pass it in the functions that display the graphics and plays the sound, every time i want to do so?
[/quote]
This is too vague for me to get a handle on what you mean, exactly. But what I will say is try not to do anything too weird or fancy unless you have a means of measuring the benefit, empirically if possible.

As to whether or not you should make things private, I have a few rules of thumb:

1. If you just clustering stuff in a class/struct as a convenient way to pass related-but-dumb data around, then it likely won't hurt to have all members public. It's quite common to reserve 'struct' for this particular usage.
2. If in doubt, make it private, as it's easier to move stuff from private to public than it is the other way
3. Don't bother with protected. It tends to get misapplied, IMHO.

Share this post


Link to post
Share on other sites
Sorry for the not-so-good-explanation.

About the data management stuff, i didn't meant things like vectors, queues, arrays, etc... What i meant is, for example, a class that handles the loading/unloading of things like graphics, 3D models, sounds, and store them in std::vectors (for instance), that could be access by other functions/classes (like the graphics-displaying class, or the sound-playing class).

And well, i've actually been programming for awhile (C++, opengl, win32, nothing fancy though), and when trying to do a bigger project, i ended up with something like this:

I had several classes, one for Logging, another for loading/playing sounds, yet another for loading fonts/displaying text, etc (which all istances of such classes declared with global scope), and, for example, i was loading a font, and wanted to write that the font was successfully loaded to a log (using the Log class), and i would access the global Log class instance to do so. But this made (again, for instance) the font class depend on the Log class defined globally. Now with almost all classes being like that, i felt it was not right, and messy (therefore this thread).But i also wasn't sure if passing by parameters was the best solution, because i kept thinking, if in a function i need 5 different class instances, i would have to pass all of them through parameters).

I hope it got a little better explained, in the end, i was looking for some guidance, on how to aproach this, in order to save me future pain.

Oh, and i'l never make the mistake of letting the 'ladies' part out of the greetings.

Share this post


Link to post
Share on other sites
For debug log, it's fine that there is a global instance logger and other code uses it, IMHO. But it would be better to wrap that global instance to some global functions, such like
[CODE]
void logMessage(const char * message)
{
globalLogger.log(message);
}
[/CODE]
So the global instance is transparent to the user code.

However, for general case, I would like to avoid global and singleton as much as possible.
Global and singleton may lead to rigid couple, hard to test, and other disadvantage.
If you google for "singletons are evil" or "singletons are bad" (no quote marks), you will find a lot of useful articles. Read them.
Such as this one,
[url="http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx"]http://blogs.msdn.co.../25/140827.aspx[/url]
Post in 2004 but it's still true for now.

Also, what you said about passing by parameters, is called dependency injection.
[url="http://en.wikipedia.org/wiki/Dependency_injection"]http://en.wikipedia....dency_injection[/url]
It's really good to substitute global or singleton. Go ahead.

BTW, your question is not about coding style. It's something about design pattern, or about singleton.
Saying coding style may confuse others.

Share this post


Link to post
Share on other sites
Here's one simple possibility for your original question:
[code]class DataManager {
//...
};

class Graphics {
DataManager &data_manager;

public:
Graphics(DataManager &data_manager) : data_manager(data_manager) {
}

//...
};


class Sound {
DataManager &data_manager;

public:
Sound(DataManager &data_manager) : data_manager(data_manager) {
}

//...
};

int main() {
DataManager data_manager;

Graphics graphics(data_manager);
Sound sound(data_manager);
}
[/code]

The general philosophy is to try to keep the classes as ignorant of the global organization of the program as possible. If I am the Sound class and I need a DataManager, I'll take a reference to it and I won't care if that's actually a global variable, a local variable in main (as in my example) or a member of some Game class.

Classes designed with this philosophy are easy to test, especially if the classes they depend on (like DataManager) are abstract classes and the testing program can provide dummy implementations specifically designed for the test.

My thoughts on this have been influenced by this talk:
[media]http://www.youtube.com/watch?v=4F72VULWFvc[/media]

Share this post


Link to post
Share on other sites
Thank you, that helps a lot!
And thanks again :)

For some reason, i never thought of saving just the reference, i just kept thinking that in each and every function that used the DataManager class, i would have to pass it as a parameter (eg: Graphics::DrawGraphics(DataManager *dataManager, ...) the ... being the rest of the parameters needed for the function. In other words, a complete mess.

Really, i can't thank you enough (and everyone else who answered, for that matter).

Share this post


Link to post
Share on other sites
Let me see if I can help out a bit here.

In a class you have normally will have two types of data, one is data that the class processes, the other type of data is data that is required for the class to work.

Data that is "required" needs to be part of the constructor because the class is not really ready to use until it has been added to the class and that data is checked to make sure that the class will function properly. They way I always look at it is if the class will not function without that item, then it MUST be added in the constructor.

So what does this mean to you? If DataManager is required to make the class work, then add it in the constructor, verify that it is valid, and then from then on you will have access to it.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this