我创建了这段代码:
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;
};
如果我没有按预期在Main.cpp中包含iostream头文件,则无法识别std :: cout。我的问题是:如果没有包含iostream,为什么在Quote.h中使用std :: ostream没有问题?在上述库中定义了cout作为ostream,为什么cout使用是一个问题而ostream不是?
我正在使用VS 2017,以防这个信息很重要。
所有现有答案都集中在#include <string>
上。我想指出另一方面。考虑稍加修改的版本:
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{};
}
如你所见#include <string>
被注释掉,quote.h
仍然不包括iostream
,程序仍然编译。这样做是因为只直接编译源文件(.cpp或翻译单元)。标题包括在内。现在,如果我们在quote.h
中包含main.cpp
,我们得到:
#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{};
}
(Qazxswpoi)
这是实际编译的内容。请注意,在online使用之前,#include <iostream>
一切顺利。
正如在对std::ostream
的评论中正确指出的那样,这是一个例子,为什么始终保持包含所依赖的所有标题的自足标题非常重要。
正如@Evgeny在评论中指出的那样,请检查another answer。
标头recommendations about organising our includes使用<string>
声明一个输出运算符。看来你正在使用的实现方式使std::ostream
普遍可用。
C ++标准定义了哪些头文件至少可以使哪些声明可用。它不禁止提供其他名称。不同的实现可以选择不使声明可用。我已经尝试严格制定我的实现中可用的强制声明,但结果并不像听起来那么简单。
您在头文件中包含std::ostream
。如果你去<string>
标题,你会看到第一行(在VS2017中):
string
并转到// string standard header
#pragma once
#ifndef _STRING_
#define _STRING_
#ifndef RC_INVOKED
#include <istream> <----- here
#include <xstring_insert.h>
标题:
istream
我认为已经回答了你的问题。但是,这取决于实现,您不应该依赖于此,而是明确包含// istream standard header
#pragma once
#ifndef _ISTREAM_
#define _ISTREAM_
#ifndef RC_INVOKED
#include <ostream> <-- here
标头。
标题iostream
提供<string>
,所以它必须确保the extraction and insertion operators for std::string
至少是前向声明的;您的代码仅使用对前导声明足够的std::ostream
的引用,以及正确声明的上述插入运算符。
因此,严格来说,标题ostream
已经提供了标题所需的所有内容,尽管为了清晰起见,我可能会明确地包含<string>
。
如果不包括
<iosfwd>
,为什么在Quote.h中使用std::ostream
没有问题?
<iostream>
间接获得<iostream>
d。
最好不要依赖这种间接的#include
s。你不能指望它在所有平台上都是真的。它甚至可能从调试版本更改为发布版本。
当你想使用一个类或一个函数时,最好查找标题,该标题应该提供类的定义和函数的声明,并且#include
直接在你的文件中。