如何使用运算符<<输出地图内容

时间:2019-05-31 09:15:08

标签: c++

我正在尝试输出地图的内容,但是不确定如何去做。我在头文件中为地图和迭代器设置了以下声明为私有

typedef map<long, string> Student;
Student newstudent;
typedef Student::const_iterator studentItr;
studentItr itr;

并且我的.cpp中有以下声明

map<long, string> classname::GetMap()
{
    for(itr = newstudent.begin(); itr !=newstudent.end(); itr++)
{
    cout << itr->first << " => " <<itr->second << '\n';
}

    return newstudent;
}

这就是我试图将其传递给重载的运算符<<函数

的方式
ostream & operator <<( ostream & os, classname & R)
{
    os << " " << R.GetMap() << '\n';

    return os;
}

通常这对其他任何功能都有效,但由于它是地图,因此出现以下错误:

  

与'operator <<'不匹配(操作数类型为'std :: basic_ostream '和'std :: map >')|

有人能指出我做错了正确的方向吗

编辑:感谢您提出建议,我感谢您的帮助,但是我认为无论是我的编译器还是我所说的话,都是不对的。

每次我尝试使用Student作为一种类型时,它都不会注册为一种类型,并且我会收到关于它的错误。

例如,如果我声明此声明

ostream & operator <<( ostream & os, const Student & R)

OR

Student & classname::GetMap()

我得到了错误:

  

“学生”没有命名类型

此错误最终导致我的陈述中没有任何意义,而且我不确定如何解决此问题

3 个答案:

答案 0 :(得分:3)

因此,由于某种原因,您似乎已经将输出代码放入GetMap函数中。您需要一个名为GetMap的例程来获取地图,或者想要一个名为PrintMap的例程来输出地图。你有一半。这是一种方法

void classname::PrintMap() const
{
    for(itr = newstudent.begin(); itr !=newstudent.end(); itr++)
    {
        cout << itr->first << " => " <<itr->second << '\n';
    }
}

ostream & operator <<( ostream & os, classname & R)
{
    os << " ";
    R.printMap();
    os << '\n';
    return os;
}

这可以改进,例如您可以将要输出的流传递给PrintMap函数。像这样

void classname::PrintMap(ostream & os) const
{
    for(itr = newstudent.begin(); itr !=newstudent.end(); itr++)
    {
        os << itr->first << " => " <<itr->second << '\n';
    }
}

ostream & operator <<( ostream & os, classname & R)
{
    os << " ";
    R.printMap(os);
    os << '\n';
    return os;
}

最后,您可以遵循通用约定,将PrintMap重命名为operator<<,并使其成为朋友函数而不是成员函数。

Student& classname::GetMap()
{
    return newstudent;
}

ostream & operator<<(ostream & os, const Student& s)
{
    for(itr = s.begin(); itr !=s.end(); itr++)
    {
        os << itr->first << " => " <<itr->second << '\n';
    }
    return os;
}

ostream & operator <<( ostream & os, classname & R)
{
    os << " " << R.getMap() << '\n';
}

答案 1 :(得分:3)

您可以为地图类型设置运算符<<。 (完全未经测试的代码)

ostream & operator <<( ostream & os, const Student & R) {
    for(studentIter itr = R.begin(); itr !=R.end(); itr++){
        os << itr->first << " => " <<itr->second << '\n';
    }
    return os;
}

编辑: 更改名称以匹配您的问题。

答案 2 :(得分:1)

最初,您尝试将std::map直接插入operator<<()中。这将不起作用,因为std::map不知道如何转换为std::ostream对象,并且std::ostream的{​​{1}}不知道如何接受地图。

您始终可以为地图类型编写operator<<()的重载,但是,如果地图内部的类型是非平凡的类型,例如具有多个字段的类或结构,则该类必须具有其重载类型也拥有自己关联的operator<<()。因此,为类型本身编写它们并在地图或集合上进行迭代更容易。

因此,既然该类与operator<<()有工作关系,您就可以遍历任何类型的容器,无论是矢量,数组,列表还是队列等。operator<<()都不在乎哪种容器,只在乎容器中的对象。

请不要养成将operator<<()operator<<()声明为类成员的习惯,请养成编写运算符的习惯,就像将一个独立的运算符函数适用于您的类型!


这是一个完整的演示:


如果您的编译器支持operator>>()代替using;您可以尝试该程序并检查其预期输出。不应有任何错误,但是在修复格式时可能会忽略一个错字。如果您找到一个,请告诉我,我会进行相应的更新。

main.cpp

typedefs

Students.h

#include "Students.h"

int main() {
    using namespace "your namespace here";

    Student JacobKnight("Jacob Knight", 233);
    Student SaraAndrews("Sara Andrews", 245);
    Student AllenReed("Allen Reed", 259);

    Students students;
    addStudent(JacobKnight, students);
    addStudent(SarahAndrews, students);
    addStudent(AllenReed, students);

    using It = std::map<long, Student>::const_iterator;
    for (It it = students.cbegin(); it != students.cend(); ++it) {
        std::cout << "Map ID: " << std::setfill('0') << std::setw(8) 
        << it->first << "\nStudent: " << it->second;
    }

    return EXIT_SUCCESS;
}

输出

#pragma once   // if your compiler doesn't like this then use header guards!

#include <iomanip>
#include <iostream>
#include <map>
#include <string>

namespace "your namespace here" {

    struct Student {
        long id_;
        std::string name_;

        Student() = default;
        Student(const std::string name, long id) : name_{name}, id_{id} {}
    };

    using Students = std::map<long, Student>;

    void addStudent(const Student& student, Students& students) {
        students.insert( std::make_pair( student.id_, student ) );
    }

    std::ostream& operator<<(std::ostream& os, const Student& student) {
        return os << std::setfill('0') << std::setw(8) << student.id_
                  << " " << student.name_ << "\n\n";
    }

} // your namespace

在这里,我想将一个学生视为一个对象,它包含该对象的详细信息,数字ID和字符数组或字符串名称。因此,我将这些作为公共成员放入了结构中。您总是可以将其更改为一个类,使用辅助函数将其私有化以封装数据,但是为了快速演示,我在这里做了一个简单的结构或类,没有什么太复杂的。

接下来,我使用using指令定义类型的类型名。现在,我以后可以轻松地使用它声明我的对象。我用它来简化Map ID: 00000233 Student: 00000233 Jacob Knight Map ID: 00000245 Student: 00000245 Sarah Andrews Map ID: 00000259 Student: 00000259 Allen Reed 的用法。我还在main中再次使用using指令将迭代器类型名称定义为It。然后,我用它来声明地图的迭代器。

我写了一个简单的函数,可以填充学生的地图。对我来说,这是更直观和更具表现力的,因为地图包含多个对象,在这种情况下为学生,因此是复数的,其中单个实体的结构本身只是一个学生!这使代码更具表现力和可读性,并有助于暗示您的意图。

然后,我简单地写了一个重载的std::map<T1,T2>,其中包含operator<<()的{​​{1}}。然后将输出格式化为我喜欢的格式或所需的布局。然后将其返回给流运算符,以插入到作为控制台或文件的标准流输出中。

我希望这个答案能回答您的问题,并为您提供一些指导...


编辑

在main.cpp中,我将映射的迭代器从for循环中的Studentconst ref更改为begin()end()。这应该没什么大不同,但是由于我地图的迭代器被声明为cbegin()。我更喜欢与遍历的迭代器类型保持一致。