我创建了以下代码:
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 。
答案 0 :(得分:2)
头文件<string>
使用std::ostream
声明输出运算符。看来您正在使用的实现方式可以使std::ostream
普遍可用。
C ++标准定义了哪些标头至少使哪些声明可用。它并不禁止使用其他名称。不同的实现可以选择不使声明可用。我已经尝试过在实现中只提供严格的强制性声明,但事实并非如此简单。
答案 1 :(得分:2)
您在头文件中包含<string>
。如果转到string
标头,您将在(VS2017)中看到第一行:
// 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
头。
答案 2 :(得分:1)
标头<string>
提供了the extraction and insertion operators for std::string
,因此必须确保std::ostream
至少是前向声明的;您的代码仅使用对ostream
的引用,对于该引用,前向声明就足够了,加上前面提到的正确声明的插入运算符。
因此,严格来说,标头<string>
已经提供了标头所需的所有内容,尽管为清晰起见,我可能会明确包含<iosfwd>
。
答案 3 :(得分:1)
如果没有包含
std::ostream
,为什么在Quote.h中使用<iostream>
没问题?
<iostream>
间接获得#include
。
最好不要依赖这种间接#include
。您不能指望在所有平台上都是如此。甚至可能从调试版本更改为发布版本。
当您要使用类或函数时,最好查找标头的标准,标头应提供类的定义和函数的声明,并#include
直接在您的标头中文件。
答案 4 :(得分:1)
所有现有答案都集中在#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{};
}
(online)
这是实际被编译的内容。请注意,在#include <iostream>
使用之前,std::ostream
在这里一切都很好。
正如在another answer的注释中正确指出的,这是一个示例,为什么始终保持自给自足的标头(包括它们所依赖的所有标头)很重要。
正如@Evgeny在评论中指出的,请检查recommendations about organising our includes。