Reputation: 425
I created this code:
Main.cpp
#include <iostream>
#include "Quote.h"
int main()
{
derived().print(std::cout);
getchar();
return 0;
}
Quote.h
#pragma once
#include <string>
class base {
public:
std::string name() { return basename; }
virtual void print(std::ostream &os) { os << basename; }
private:
std::string basename = "abc";
};
class derived : public base {
public:
void print(std::ostream &os) { base::print(os); os << " " << i; }
private:
int i = 0;
};
If I don't include the iostream header file in Main.cpp, as expected, std::cout is not recognized. My question is: Why there's no problem with the use of std::ostream in Quote.h if iostream is not included?. Either cout as ostream are defined in the aforementioned library, why the cout use is a problem and ostream not?
I'm using VS 2017, in case this info is important.
Upvotes: 4
Views: 1026
Reputation: 16286
All existing answers concentrate on #include <string>
. I'd like to point at another side. Consider slightly modified version:
quote.h
:
#pragma once
// uncomment to get an analog of original example
// #include <string>
struct Quote {};
std::ostream& operator<<(std::ostream& os, Quote const&)
{
return os << "quote\n";
}
main.cpp
:
#include <iostream>
#include "quote.h"
int main()
{
std::cout << Quote{};
}
As you see #include <string>
is commented out, quote.h
still doesn't include iostream
and the program still compiles. It does because only source files (.cpp, or translation units) are directly compiled. Headers are literally included. Now if we literally include quote.h
in main.cpp
we get:
#include <iostream>
// uncomment to get an analog of original example
// #include <string>
struct Quote {};
std::ostream& operator<<(std::ostream& os, Quote const&)
{
return os << "quote\n";
}
int main()
{
std::cout << Quote{};
}
(online)
It's what actually gets compiled. Notice everything is alright here, #include <iostream>
before std::ostream
usage.
And as was correctly pointed in comment to another answer, this is an example why it's important to always maintain self-sufficient headers that include all headers they depend on.
As @Evgeny pointed out in the comment, please check recommendations about organising our includes.
Upvotes: 3
Reputation: 206727
Why there's no problem with the use of
std::ostream
in Quote.h if<iostream>
is not included?
<iostream>
get #include
d indirectly.
It's best not to rely on such indirection #include
s. You can't count on it being true on all platforms. It may even change from debug build to release build.
When you want to use a class or a function, it's best to lookup the standard for the header that's supposed to provide the definition of the class and the declaration of the function, and #include
the header directly in your file.
Upvotes: 1
Reputation: 126937
The header <string>
provides the extraction and insertion operators for std::string
, so it has to make sure that std::ostream
is at least forward-declared; your code only uses a reference to ostream
, for which a forward declaration suffices, plus the aforementioned insertion operator, which is correctly declared.
So, strictly speaking, all that is needed by your header is already provided by the header <string>
, although I'd probably explicitly include <iosfwd>
for clarity.
Upvotes: 1
Reputation: 2135
You include <string>
in your header file. If you go to the string
header you will see the first lines as (in VS2017):
// string standard header
#pragma once
#ifndef _STRING_
#define _STRING_
#ifndef RC_INVOKED
#include <istream> <----- here
#include <xstring_insert.h>
and going to the istream
header:
// istream standard header
#pragma once
#ifndef _ISTREAM_
#define _ISTREAM_
#ifndef RC_INVOKED
#include <ostream> <-- here
which I think already answers your question. However, this is implementation dependent and you should not rely on this but include explicitly the iostream
header.
Upvotes: 2
Reputation: 154035
The header <string>
declares an output operator using std::ostream
. It seems the implementation you are using does so in a way making std::ostream
generally available.
The C++ standard defines which headers make which declarations available at least. It doesn’t prohibit against additional names being made available. Different implementations may choose to not make the declarations available. I have tried making strictly only mandated declarations available in my implementation but this turns out to be not quite as simple as it sounds.
Upvotes: 2