std::ostream 识别而不定义 header

std::ostream recognize without defining header

我创建了这段代码:

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 header 文件,std::cout 无法识别。我的问题是:为什么在 Quote.h if iostream[ 中使用 std::ostream 没有问题=35=]不包括在内?。在上述库中定义了 coutostream,为什么 cout 使用是一个问题并且 ostream 不是吗?

我正在使用 VS 2017,以防此信息很重要。

header<string>提供the extraction and insertion operators for std::string,所以要保证std::ostream至少是forward-declared;您的代码仅使用对 ostream 的引用,前向声明就足够了,加上前面提到的正确声明的插入运算符。

因此,严格来说,header 已经提供了 header 所需的所有内容,尽管我可能会明确包括 <iosfwd>明晰。

header <string> 使用 std::ostream 声明输出运算符。您正在使用的实现方式似乎使 std::ostream 普遍可用。

C++ 标准定义了哪些 header 使哪些声明至少可用。它不禁止提供其他名称。不同的实现可能会选择不使声明可用。我曾尝试在我的实现中严格只提供强制声明,但事实证明这并不像听起来那么简单。

您在 header 文件中包含 <string>。如果您转到 string header,您将看到第一行(在 VS2017 中):

// string standard header
#pragma once
#ifndef _STRING_
#define _STRING_
#ifndef RC_INVOKED
#include <istream> <----- here
#include <xstring_insert.h>

并前往 istream header:

// istream standard header
#pragma once
#ifndef _ISTREAM_
#define _ISTREAM_
#ifndef RC_INVOKED
#include <ostream> <-- here

我想这已经回答了你的问题。然而,这是依赖于实现的,你不应该依赖它,而是明确地包含 iostream header.

Why there's no problem with the use of std::ostream in Quote.h if <iostream> is not included?

<iostream> 间接获得 #included。

最好不要依赖这种间接 #includes。您不能指望它在所有平台上都是正确的。它甚至可能从调试版本更改为发布版本。

当您想使用 class 或函数时,最好查找 header 的标准,它应该提供 class 的定义和声明函数,#include header 直接在您的文件中。

现有答案全部集中在#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 或翻译单元)是直接编译的。 Headers 确实包括在内。现在,如果我们从字面上将 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 的评论中正确指出的那样,这就是为什么始终维护 self-sufficient headers 非常重要的一个例子,其中包括它们所依赖的所有 headers .

正如@Evgeny 在评论中指出的,请检查recommendations about organising our includes