std :: ostream在不定义标题的情况下识别

问题描述 投票:2回答:5

我创建了这段代码:

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,以防这个信息很重要。

c++ visual-studio header-files iostream
5个回答
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{};
}

(Qazxswpoi)

这是实际编译的内容。请注意,在online使用之前,#include <iostream>一切顺利。

正如在对std::ostream的评论中正确指出的那样,这是一个例子,为什么始终保持包含所依赖的所有标题的自足标题非常重要。

正如@Evgeny在评论中指出的那样,请检查another answer


2
投票

标头recommendations about organising our includes使用<string>声明一个输出运算符。看来你正在使用的实现方式使std::ostream普遍可用。

C ++标准定义了哪些头文件至少可以使哪些声明可用。它不禁止提供其他名称。不同的实现可以选择不使声明可用。我已经尝试严格制定我的实现中可用的强制声明,但结果并不像听起来那么简单。


2
投票

您在头文件中包含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 标头。


1
投票

标题iostream提供<string>,所以它必须确保the extraction and insertion operators for std::string至少是前向声明的;您的代码仅使用对前导声明足够的std::ostream的引用,以及正确声明的上述插入运算符。

因此,严格来说,标题ostream已经提供了标题所需的所有内容,尽管为了清晰起见,我可能会明确地包含<string>


1
投票

如果不包括<iosfwd>,为什么在Quote.h中使用std::ostream没有问题?

<iostream>间接获得<iostream>d。

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

当你想使用一个类或一个函数时,最好查找标题,该标题应该提供类的定义和函数的声明,并且#include直接在你的文件中。

© www.soinside.com 2019 - 2024. All rights reserved.