I'm fairly new to C++, but my understanding is that a #include statement will essentially just dump the contents of the #included file into the location of that statement. This means that if I have a number of '#include' and 'using' statements in my header file, my implementation file can just #include the header file, and the compiler won't mind if I don't repeat the other statements.
What about people though?
My main concern is that if I don't repeat the '#include', 'using', and also 'typedef' (now that I think of it) statements, it takes that information away from the file in which it's used, which could lead to confusion.
I am just working on small projects at the moment where it won't really cause any issues, but I can imagine that in larger projects with more people working on them it could become a significant issue.
An example follows:
UPDATE: my function prototypes for 'Unit' have string, ostream and StringSet among their return types and parameters - I am not including anything in my header file that is used only in the implementation file.
//Unit.h
#include <string>
#include <ostream>
#include "StringSet.h"
using std::string;
using std::ostream;
class Unit {
public:
//public members with string, ostream and StringSet
//in their return values/parameter lists
private:
//private members
//unrelated side-question: should private members
//even be included in the header file?
} ;
//Unit.cpp
#include "Unit.h"
//The following are all redundant from a compiler perspective:
#include <string>
#include <ostream>
#include "StringSet.h"
using std::string;
using std::ostream;
//implementation goes here
(ʃʊd ) verb. the past tense of shall: used as an auxiliary verb to indicate that an action is considered by the speaker to be obligatory (you should go) or to form the subjunctive mood with I or we (I should like to see you; if I should be late, go without me) See also shall.
must, need, ought (to), shall.
[M] [T] You should take an umbrella with you this morning. [M] [T] You should make sure that you don't make Tom angry. [M] [T] She agreed with him that I should go to the meeting. [M] [T] Parents should spend quality time with their children.
A using-directive (using namespace std;
) should not reside in a header unless it is contained within a function. It is bad practice. It is unlikely that every user of your header wants unqualified lookup for everything in a given namespace; the inclusion of unrelated headers can lead to unexpected ambiguity and compilation failures. Personally, I avoid the using-directive inside of functions for the same reasoning, but this is generally considered less harmful.
A type alias (either through typedef std::string string;
or using string = std::string;
) should be used carefully. Type definitions have meaning, so you should never redeclare it. For example, this is an error:
typedef int myint;
typedef float myint;
because of conflicting types.
A using-declaration (using std::string;
or using std::memcpy;
) makes a symbol accessible for unqualified name lookup. It is extremely useful when getting for argument-dependent lookup correct, which usually doesn't matter unless you're writing a library. The advice is different depending on if you are bringing in a type or a function. Think of using-declarations with types in the same manner as a type alias: It does not make sense to have multiple definitions under the same name. With functions, all you are really doing is extending overload resolution to include a few more things (although it is usually not necessary).
// Finding multiple operator<< functions makes sense
using std::operator<<;
using mylib::operator<<;
// Finding multiple string classes does not make sense
using std::string;
using mylib::string;
For repeating #include
, you should consider if you actually need to include the file in the header in the first place. Perhaps a forward declaration fits your needs.
using
statement in headers (unless inside function scopes)... Adding using
in the header will pollute the namespaces of all the sources including the header.You don't need to care if some includes are redundant. Header guards and precompiler optimizations are there to handle that for you.
You should be able to manipulate each file in isolation.
For example, let's say you use the std::string
in the header and in the source, but, as an "optimization", you only included the string in the header... If you discover later you don't need anymore the string in the header, and want to remove it (code cleaning, and all...), you will have to modify the source to include the string. Now, let's imagine you have TEN sources including the header...
Now, of course, you can have exceptions to this rule (for example, precompiled headers, or even headers woe sole aim is to do multiple includes as a courtesy), but by default, you should have self-sufficient header and source files (i.e. files that include anything they use, no more no less).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With