Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly structure OOP and multifile projects?

As a beginner programmer, just now learning the basics of OOP, I've run into many issues with the basic inclusion structure of my practice programs. I've been teaching myself programming using various written and online resources. But, here's my problem (well, one of them...):

On one hand, I understand the importance of abstraction, encapsulation, and having a low degree of coupling between classes, yet, on the other hand, I've been struggling tremendously with structuring my program and designing my classes in a way that allows different classes in different files to know about each other.

Of course, this is a major problem of mine that has resulted in sloppy, hackish code which only works the way I want it to after I throw every basic principal OOP out the window and start filling my code with globals variables, forward declarations of everything everywhere, and making class members public.

Simply put: My programming is a mess... C++ is my first programming language, and even when I try my best to design/write in an object orient way, I end up with an ugly mess of files, #including everything in nearly every file, and an odd mix of procedural and OOP spaghetti code that rarely works!

I'm a self-proclaimed programming novice, and I accept that it takes time to learn how to structure a program, but I'm nearly at wit's end! I know that my problem stems from the fact that I know a little bit about OOP. I know that I want to write independent classes that handle a single task. But at the same time, I don't understand how to properly alert each class of the existence of the other parts of the program. It's a little bit like knowing what kinds of food you should eat but not knowing how to use a fork...

That's my problem in a nutshell. And to further follow up with some more specific questions that I have:

  • In C++ multifile project, is it normal/needed to put the main() function inside a class of its own? Or is it the standard thing to leave your main() in the global scope?

  • In previous, procedural programs that I've written in C++, it wasn't uncommon to have a constants variables or #defines in the global scope, at the top of main.cpp file. For example, maybe the dimensions of the screen or other useful information would be defined at the start of the program. What happens in OOP? Is this practice to be avoided completely? Or do I make a MAIN.H file and #include it in every other header in the project? I have no idea what to do about this...

  • When writing my first medium size practice OOP program, my work came to a screeching halt when I began trying to write a StateMachine class. It was my intention to have the StateMachine class contain all the possible screen states that the program would use. However, an issue arose where my StateMachine class seemed to not be aware of some of my other State classes, even though they were all #included. I've seen people do forward declarations of classes before, is that necessary? Should I be spamming forward declarations of classes all over the place or is that a code smell?

  • Finally, does the order of #include and forward declaration commands matter?

I know this is probably a super basic question, but it's something that has been giving me a really hard time in my transition from single-file procedural c++ beginner programs to multi-file OOP programming. Is there some general rule of thumb for structuring your programs so that everything just works? I've been using include guards, so is there any reason why one can't just #include every header in every source file? Should I have a common.h file that is #included in each header file for each class?

I really appreciate any help/advice that the community can give me. I know that this is a simple, yet important hurdle for me to pass before I can begin developing my OOP skills. I've been trying to drill into my brain the importance of keeping classes separate from each other to the point where I'm not sure how to really set up my classes/files in a way that allows them to really interact with each other! Thanks so much for the help!

like image 353
MrKatSwordfish Avatar asked Aug 13 '12 11:08

MrKatSwordfish


1 Answers

You can't think of OOP as of normal functional programming with classes. This is a wrong approach and it is going to mislead you.

Designing the architecture of your application is extremely important, there are whole books written about it. The better you design your app's structure, the easier it will be for you to code, and the less errors you are going to have. It is a good advice to learn the basics of some modeling language to make it easier for you to draw and understand stuff. UML is a great choice for it.

There are two approaches for designing big stuff. You can descend, which means you start on a high level of abstraction, and go down, narrowing your problems. Or you can ascend, starting with implementing little things which are easy to do, and then going up, connecting yuor small modules into an app.

You can easily find a lot of info about that on the web. That's in a nutshell. Now, for your specific questions.

  1. Leave main in a global scope. Personally, I even leave it in a separate main.cpp file to keep it clean, but it doesnt really matter where do you put it.

  2. Try to avoid global variables. If you need constants, it's ok to define them. And yes, your approach with all the defines in a single header file works well. However, you may want to separate them by meaning, not to include a file with 10000 defines into a .cpp that needs just one of those.

  3. If you need to use a class before it's declared, you'll have to forward-declare it, otherwise the compiler will not know it's there.

  4. The order of includes does matter, because each #include basically copypasts the text of the corresponding file. So if you #include your class.h in your class.cpp, the header's text will be just copy pasted into the source file by the preprocessor. The order of forward declaration does not really matter as long as you forward declare stuff before you first use it.

like image 117
SingerOfTheFall Avatar answered Oct 31 '22 13:10

SingerOfTheFall