8

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!

MrKatSwordfish
  • 1,414
  • 5
  • 18
  • 28
  • 1
    For better understanding of OOP why not try playing with Java or C# or even better python (IMO, it's the best point to try in your case)? C++ is one of the most powerful languages without any question but it's headache (for me anyway) working with classes in C++ – Leri Aug 13 '12 at 11:46
  • 1
    @PLB: I [sincerely recommend](http://stackoverflow.com/questions/713704/c-as-a-first-language/713735#713735) learning C++ first and "pure OO" / garbage collected languages second. It makes for a very solid foundation, avoids several flavors of design / implementation mistakes, and makes for a much easier transition later on. Learning Java / C# / Python first *in order to* learn C++ second is a *definite* mistake. – DevSolar Aug 13 '12 at 13:49
  • 1
    @DevSolar I don't argue that learning C++ first gives you big advantage and better understanding how to write efficient code. But as OP mentioned he has experience with c++ with writing procedural codes. He actually has problem(s) with understanding and/or practical use of OOP designs. Python/Java/C# could give him idea in few days. I'm not very experienced, so maybe I am wrong. This's just my opinion. – Leri Aug 13 '12 at 14:06

3 Answers3

4

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.

SingerOfTheFall
  • 27,171
  • 7
  • 60
  • 100
4
  • C++ is more than OOP, it is multiple-paradigm. Don't try to press everything through the OO filter, this does C++ a disservice. In several places, C++ can do things more elegantly because you are not limited to "pure" OO. For example,

  • main() is never inside a class, and always at global scope.

  • The most important rules are "consistency" and "maintainability". Think about how you will look at the program later, once it's "finished" and you want to fix a couple of bugs. Where will you find constants and defines the easiest way?

  • If the sequence of #includes matter, your header files are broken. Each header should be (minimally) self-sufficient for the things declared in it.

  • One class declaration per header, one class definition per implementation unit. File and class bear identical names. Really, this is about the only rule that I consider non-negotiable. Having to grep for information about a class is orders of magnitude more inconvenient than finding it.

The rest, really, can be found in every good book on C++, and you really should work with a book instead of threading your way through tutorials and Q&A pages.

DevSolar
  • 59,831
  • 18
  • 119
  • 197
  • 2
    I know what you mean, and I agree, but the rule should not really be a class per file, but rather a *component* per file, with the name of the file being the main class (and thus the *component* and the class sharing the name). Why this distinction? The definition of a helper type (example: the iterator that navigates the container) should be together with the helped class (the container). +1 – David Rodríguez - dribeas Aug 13 '12 at 12:34
  • 1
    @DavidRodríguez-dribeas: ACK for iterators, which are pretty integral part of a class. But far too often I've seen "helper" classes grow far beyond their initial concept, being used all over the place (in other namespaces, even, cleverly hidden behind a `using namespace` declaration) - and it's damn annoying having to track them down trying to figure out what they're actually *doing*... – DevSolar Aug 13 '12 at 12:51
  • Thank you for the advice! I'm always interested in learning from books and ebooks, and I already own a few. The unfortunate side effect of teaching yourself is that you don't have professors or peers to bounce ideas off of when you get stuck on something, regardless of how simple it is! Because of that, I really appreciate the insight of people on this site. I'll definitely be taking all of this advice and looking at my various resources again to see if I can develop a better understanding of program structure. Thanks for your time! :) – MrKatSwordfish Aug 14 '12 at 03:06
  • 1
    @MrKatSwordfish: Take a look at available sources. If you understand them well, note what makes them understandable, and attempt to emulate it. If you have problems understanding it, note the "why", and avoid it. – DevSolar Aug 14 '12 at 05:21
1

ok... So the main problem seems to be keeping an OO organization of your file. first and foremost if you haven't read the Google C++ Style Guide i would stongly advice you to do so. I also found this previous answer that is rather clear and simple

I hope this help

Community
  • 1
  • 1
MimiEAM
  • 2,170
  • 1
  • 23
  • 27
  • 3
    While there are many good hints in the Google Style Guide, there are also several not-so-good ones in it, more appropriate for re-training Java developers, which put a horrible crimp into C++ style. Disallowing exceptions, casually allowing output parameters, disallowing default arguments, discouraging use of C++11 / "unapproved" Boost libraries, stuff like that. It's a style guide for *Google* internal work, not really generic "best C++ practice". – DevSolar Aug 13 '12 at 12:18