Sign in to follow this  
Bluefirehawk

how is stuff done correctly in the C++ World (headers, #include,namespaces)?

Recommended Posts

I am coming from the Java/C# world. Now I am a bit confused how you do stuff in C++.


[b]Nested Namespaces?[/b]
I am used deep nested namespaces and to also have my folder structure according to the them (For example "Core/System", "Core/Graphics/Textures"...). Now I read that in C++, nesting namespaces is not encouraged and is only used to prevent nameclashes.
Is that how you do it in C++? Does a deep folder structure make sense for a C++ project, or is a shallow structure considered standard?


[b]How to include correctly? Observer pattern example[/b]
to illustrate my problem, let's say I have an Observer/Observable pattern implemented:
/Core/Observable.h
/Core/Observable.cpp
/Core/Message.h
/Core/Message.cpp
/Observer.h
/Observer.cpp

Now for the Observable can:
#include "Message.h" of
declares "class Message;"

The Observer can:
#include "Observable.h", and implicitly know about the Message class as well, if Observable uses Method 1
#include "Observable.h", #include "Message.h", thanks to header guards this works.
#include "Observable.h" and declare "class Message;"

What's the "right" way to do it, or is there none?


[b]nested headers[/b]
I don't know if it is a religious topic, but some sources say nested headers are baaaad. are they?

I saw something like:
global.h
(header guard)
#include <std>
#include "utilities.h"
#include ...

every file included globals.h, is this a common practice or is it stupid?

Share this post


Link to post
Share on other sites
[quote name='alvaro' timestamp='1344343691' post='4966993']
[quote name='Bluefirehawk' timestamp='1344331849' post='4966955']
[b]Nested Namespaces?[/b]
I am used deep nested namespaces and to also have my folder structure according to the them (For example "Core/System", "Core/Graphics/Textures"...). Now I read that in C++, nesting namespaces is not encouraged and is only used to prevent nameclashes.
Is that how you do it in C++? Does a deep folder structure make sense for a C++ project, or is a shallow structure considered standard?
[/quote][/quote]

There is one notable exception though, it can be useful to have a subnamespace detail or impl. That becomes mostly useful in large multi-people projects but a subnamespace like that is a warning to every right-thinking person that anything in there should not be touched (unless you really, really know what you are doing and you can live with the fact that the next version of that library might not work with your code, at all).

Share this post


Link to post
Share on other sites
[quote name='alvaro' timestamp='1344343691' post='4966993']
You should generally prefer a forward declaration if that's enough (i.e., if you are only going to declare pointers or references to the class), especially in header files. That way compiling a module won't require reading an extra header file, and a change in the header file will trigger recompilation of fewer modules.
[/quote]

Okeeey... so for example the Observable.h would look like this:
[CODE]
class Observable
{
class Message;
private:
...
void NotifyObservers(Message me);
...
}
[/CODE]
this would be the best way to do it (considering includes and not the public function).
but then under the same rules it would make sense to just forward declare on the Observer.h as well, and now I have never included the Message.h and the program will probably not link correctly.

In other words, when do I ever use an object in the header file and do more with it than just declaringreference/pointers? Thats what the cpp files are for, i thought.
Thanks for the reply, but it's still not very clear to me. Edited by Bluefirehawk

Share this post


Link to post
Share on other sites
I wouldn't put a forward declaration inside a class block: C++ has nested classes, so you probably just forward-declared Observable::Message. Also, you can't use a forward declaration in your case, because you are passing a Message by value. If you pass a reference or a pointer instead, it should be fine.

You probably have some part of the program that needs to use the Message class, and at that point you'll need to include Message.h.

If forward declarations are confusing you right now, start by not using them, which is not terrible in most circumstances. When you are more familiar with how header files are used in C++, you can start using them.

Oh, while we are talking about header files in C++: Make sure the first thing you do in foo.cpp is include foo.h. That way you verify that you didn't miss any dependencies in foo.h and it can be compiled by itself. Edited by alvaro

Share this post


Link to post
Share on other sites
edited post because I mainly use pointers and then I realized it doesnt work on non-pointers.

this is the error you will get:

In file included from main.cpp:10:0:
Observer.h:16:10: error: field 'myMessage' has incomplete type

[source lang="cpp"]
class Message;
class Observer {
Message myMessage;
void accessMessage();
}
[/source]

so actually this gives no error:

[source lang="cpp"]
class Message;
class Observer {
Message* myMessage;
void accessMessage();
}
[/source]

this actually doesn't give an error message either:

[source lang="cpp"]
class Message;
class Observer {
Message* myMessage;
void accessMessage() {
myMessage->someFunc();
}
}
[/source]

But trying to access Observer::accessMessage without including the Message header will give an error:

In file included from main.cpp:10:0:
Observer.h:17:49: error: invalid use of incomplete type 'class Message'
Observer.h:11:7: error: forward declaration of 'class Message'

[source lang="cpp"]
#include "Observer.h"

int main(int argc, char** argv) {

Observer myObserver;
myObserver.accessMessage(); // error


return 0;
}
[/source]

To fix the error you will need to include the actual header of Message so it knows about the actual functions.

This is the way I usually set up my files:

[source lang="cpp"]
// .h file
class Message;
class Observer {
Message* myMessage;
void accessMessage();
}

// .cpp file
#include "observer.h"
#include "message.h"

void Observer::accessMessage() {
myMessage->someFunc();
}
[/source]

And without pointers:

[source lang="cpp"]
// .h file
class Observer {
Message myMessage;
void accessMessage();
}
// .cpp file
#include "message.h"
#include "observer.h"
void Observer::accessMessage() {
myMessage.someFunc();
}
[/source] Edited by eFoDay

Share this post


Link to post
Share on other sites
Alrigth, forward declaration starts to make sense.
Then I have one last hassle, why do you put your includes in the .cpp files? The Headers can compile without any other classes now, but the body cannot. Is there an upside/downside?

Share this post


Link to post
Share on other sites
[quote name='Bluefirehawk' timestamp='1344406250' post='4967270']
Then I have one last hassle, why do you put your includes in the .cpp files? The Headers can compile without any other classes now, but the body cannot. Is there an upside/downside?
[/quote]

One of the main reason to do this is to reduce compile-time dependencies between modules and classes by separating the implementation from the declaration in the headers. This will increase the compile-speed and also allow you to separate modules better. Usually you only need to know the [i]declaration[/i] (method-footprints) of a class and not the [i]definition[/i] (implementation) of said methods in another class. The problem behind it is, that in c++ includes are always visible from the outside even if all the methods and class-attributes are declared private.

One of the downside of forward declaration is, that you can only use forward declared classes by using pointers and references and not by value, which may be a bit confusing if you are used to Java/C#.

Here is a simple example:
Say you have a base class "MyBaseClass" which internally (private) uses some helper class and another class that inherits from MyBaseClass. If you include the helper-class in your header like this:

[source lang="cpp"]
// file MyBaseClass.h
#include "SomeHelperClass"

class MyBaseClass
{
public:
// whater is needed
private:
SomeHelperClass myImplementationHelper;
}


// file MyDerivative.h
#include "MyBaseClass.h"
class MyDerivative : public MyBaseClass
{
public:
... // whatever you need
}
[/source]

If you have changes in [i]SomeHelperClass.h[/i] the compiler will of course recompile MyBaseClass which directly uses the helper. But since you indirectly include SomeHelperClass.h also in MyDerivative this will also be recompiled even if MyDerivative has not changed at all. So you compile three cpp files instead of only two. Would you use a forward declaration of SomeHelperClass in your base class and only include the header in MyBaseClass.cpp, you would only need to compile two.

I hope this helps.

[size=1]edited some typos[/size] Edited by doeme

Share this post


Link to post
Share on other sites
[quote name='Bluefirehawk' timestamp='1344406250' post='4967270']
Alrigth, forward declaration starts to make sense.
Then I have one last hassle, why do you put your includes in the .cpp files? The Headers can compile without any other classes now, but the body cannot. Is there an upside/downside?
[/quote]

Generally include directives should be in the .cpp file only, if at all possible. Perhaps this is easier to illustrate with an example.

Say you have a class `AI_Agent' that has a method `pick_action'. Picking an action in this particular game involves using a GOAP planner, but this fact is not part of the interface of AI_Agent. So we'll include GOAP_Planner from AI_Agent.cpp, but not from the header file. If you were to put that include directive in the header file, any module that includes AI_Agent.h would have to compile GOAP_Planner.h, and would need to be recompiled if GOAP_Planner.h were changed.


The AI_Agent could keep a pointer to the GOAP_Planner it's using and that would have to be reflected in the class{...} block, which is in the header file. In that case, a forward declaration will allow for the use of the pointer, and users of AI_Agent have no need to know the details of that class.

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