Separate header files for declarations and definitions

Started by
6 comments, last by rip-off 11 years, 9 months ago
I often use forward declaration of classes in my header files in order to avoid including unnecessary class headers and thus increasing dependencies (and therefore compile times). E.g.

class A; // Avoids having to include "A.h"

class B {
public:
    SomeFunction(A* parameter); // Compiler is happy, because A has been declared
};

However, Scott Meyers Effective C++ (3rd edition, page 144) suggests that it is best practise to actually put these forward declarations into a separate header file and include that instead of the forward declaration. For instance, in the above example class A would be split into 3 files: * A.h - The definitions * A.cpp - The implementations * A_fwd.h - The forward declarations (but no definitions or implementations) A_fwd.h would be included in the above code, rather than explicitly declaring class A. My query is though, is this really beneficial and do people really follow this practise? The justification for this best practise seems to be that if a class declaration changes then you only have to change it in one place (the declaration header). This doesn't see to make sense though for two reasons: * Why would my class declaration change? My definitions and implementations may but the forward declaration simply states that a class of that name exists. If I decided to rename a class then ok, but... * Even if I did change the declaration, I still have to visit all my class definitions & implementations and rename the class everywhere it's used! (This could be avoided if I'm using pimpl unless it's the interface class that's changing, but I don't think we need to get into that). Any thoughts? Cheers! :)
Advertisement
Quote:Original post by tharris997
My query is though, is this really beneficial and do people really follow this practise? The justification for this best practise seems to be that if a class declaration changes then you only have to change it in one place (the declaration header). This doesn't see to make sense though for two reasons:


I would say that how beneficial this is really just depends on the project it is being used on. I mean we can throw out opinions all day, bu when it comes down to it, how beneficial something is really lies in the beholder. I myself normally don't take this approach, but I've recently found it more useful in my current project, a network library.

The larger issue being addressed is that of a Public and Private API for your code. The public API would be why you have "A_fwd.h" and the private API is the full api in "A.h". At times, it is necessary to expose some functionality in a class that you might not want users to have access to. In this case, the most elegant way to solve this is by having the setup described. The public API should rarely change, since it would break any implementations using it, whereas the private API can be changed by the developer at will and no one is affected since the public API will still do what it is supposed to, even if it is now in a different way.

The other approach I've seen in hiding the private API from the public API would be as follows:
struct MyClassPrivateData;class MyClass{private:   MyClassPrivateData * myHiddenData;...};

In this case, the public API would never know what is in the MyClassPrivateData structure, so it accomplishes internal data hiding. However, it is a bit ugly and you then have to add myHiddenData-> calls all in your code as well as manage the memory. That can get a bit icky, so using another means to hide the API can be useful.
I don't see a point in wrapping a forward declare in a header file, it sounds like overkill for very little benefit.
Quote:Original post by Drew_Benton
I would say that how beneficial this is really just depends on the project it is being used on. I mean we can throw out opinions all day, bu when it comes down to it, how beneficial something is really lies in the beholder. I myself normally don't take this approach, but I've recently found it more useful in my current project, a network library.


Very true, but I'd actually like to hear a few opinions because they often shed light on something I've not considered. :)

Quote:Original post by Drew_Benton
The larger issue being addressed is that of a Public and Private API for your code. The public API would be why you have "A_fwd.h" and the private API is the full api in "A.h". At times, it is necessary to expose some functionality in a class that you might not want users to have access to. In this case, the most elegant way to solve this is by having the setup described. The public API should rarely change, since it would break any implementations using it, whereas the private API can be changed by the developer at will and no one is affected since the public API will still do what it is supposed to, even if it is now in a different way.


The case I'm describing is not intended to address public/private API issues. Perhaps I wasn't clear though - A_fwd.h isn't an API, it contains ONLY the forward declarations for the class (no definitions). For instance, A_fwd.h would look like this:

#ifndef A_FWD_H#define A_FWD_Hclass A;#endif


That's all! So as you can see it couldn't be used as a public API.

Quote:Original post by Drew_Benton
The other approach I've seen in hiding the private API from the public API would be as follows:
struct MyClassPrivateData;class MyClass{private:   MyClassPrivateData * myHiddenData;...};

In this case, the public API would never know what is in the MyClassPrivateData structure, so it accomplishes internal data hiding. However, it is a bit ugly and you then have to add myHiddenData-> calls all in your code as well as manage the memory. That can get a bit icky, so using another means to hide the API can be useful.


What you're describing here is the pimpl idiom - hiding object implementation behind a pointer. It's a great solution to public/private API issues as well as minimizing compilation dependencies. Unfortunately, I don't believe it's directly related to the practise I'm describing - having separate header files for declarations and implementations.

Cheers!

Quote:Original post by AAA
I don't see a point in wrapping a forward declare in a header file, it sounds like overkill for very little benefit.


That's what I'm thinking but will happily be proven wrong, if someone can justify this :)

Thanks!
Quote:Original post by AAA
I don't see a point in wrapping a forward declare in a header file, it sounds like overkill for very little benefit.


It is overkill if you're wrapping class A; in a header, but when you're wrapping multiple lines, then it's a line-saver. [smile]

Consider the forward declaration for std::string:
#ifndef STRING_FWD_H#define STRING_FWD_Hnamespace std{	template<typename type> struct char_traits;	template<typename type> class allocator;	template<typename type, typename traits, typename alloc>	class basic_string;	typedef basic_string<char, char_traits<char>, allocator<char> > string;};#endif  // STRING_FWD_H


Or classes in namespaces:

#ifndef GRAPHICS_DEVICE_FWD_H#define GRAPHICS_DEVICE_FWD_Hnamespace my_engine{	namespace graphics	{		class device;	};};#endif  // GRAPHICS_DEVICE_FWD_H
Hi there!

I know this topic is a bit old (4 years old :D ), but it's really interesting?

Anyone with a clear explanation about that?
Please do not post in old threads.

This topic is closed to new replies.

Advertisement