std :: ostream识别而无需定义头

时间:2018-08-18 21:31:17

标签: c++ visual-studio header-files iostream

我创建了以下代码:

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

5 个答案:

答案 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