如何重载运算符<<对于一个班级成员?

时间:2015-10-02 05:20:49

标签: c++

假设我想要打印一个类成员,我试图为成员重载operator<<

#include <iostream>
#include <map>

template <typename K, typename V>
class MyClass {
 public:
  typedef std::map<K, V> MyMapType;
  MyMapType mymap;
  friend std::ostream& operator<<(
      std::ostream& _os, const typename MyClass<K, V>::MyMapType& _map) {
    for (auto p : _map) _os << p.first << std::endl;
  }
};

int main(int argc, char const* argv[]) {
  MyClass<std::string, int> c;
  c.mymap["a"] = 1;
  c.mymap["b"] = 2;
  std::cout << c.mymap << std::endl;
  return 0;
}

但编译器似乎忽略了定义:

error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'MyMapType' (aka
      'map<std::__1::basic_string<char>, int>'))
  std::cout << c.mymap << std::endl;
  ~~~~~~~~~ ^  ~~~~~~~

那我该怎么正确地重载这个呢?我是否必须在类中创建一个类,或者我是否需要提供std :: map的派生?

2 个答案:

答案 0 :(得分:2)

它只需要在课外:

template <typename K,typename V>
std::ostream& operator<<(
   std::ostream& _os, 
   const std::map<K,V> _map
) {
   for (auto& p : _map) _os << p.first << "\n";
   return _os;
}

这是有效的,因为MyMapType只是std::map的别名,因此如果要打印MyMapType的实例,则只需打印常规std::map。< / p>

您的原始示例不起作用,因为您没有MyClass类型的参数,因此无法在MyClass中找到该函数。朋友函数只能在类外部声明,或者如果它们具有类的类型参数,则只能在类外找到。

答案 1 :(得分:0)

对不起,@ Vaugh Cato,但问题与friend声明无关。无论如何都没有必要,因此应该避免。

@chad luo:“一流的朋友功能”应该是什么?这没有任何意义。

此处编译器错误消息具有误导性。找不到该功能,因为它不存在。您已在左侧定义了一个运算符MyClass<...>,右侧是流和地图。在找不到合理的声明之前,编译器应该抱怨无意义的声明。

如果您将运算符定义为成员函数,则运算符的左参数始终为this

class A { /*...*/ };
class B { /*...*/ };
class C {
    public:
        A operator << (const B& rhs);
    /*...*/
};

C c;
B b;
A a = c << b;

对于流操作,您需要在左侧使用流对象,在右侧使用this。理论上,您可以在流类中指定运算符,但不能在用户类中指定。由于流类来自标准库,因此不是一个选项。所以你只需使用外部运算符定义。您可以在里面调用成员函数,以避免声明流操作符friend

class A {
    public:
        writeToStream(std::ostream& stream) const;
    /*...*/
};

std::ostream& operator << (std::ostream& stream, const A& a) {
    a.writeToStream(stream);
    return stream;
};

这些函数都不必声明为friend。避免像瘟疫一样friend。只有极少数非常罕见的情况才需要它。不要使用它,只要你不是100%确定,你的情况就是其中之一。

所以这里是完整的示例更正(未经测试,因此要注意错误):

#include <iostream>
#include <map>

template <typename K, typename V>
class MyClass {
   public:
      typedef std::map<K, V> MyMapType;
      MyMapType mymap;
};

template <typename K, typename V>
std::ostream& operator<<(std::ostream& stream,
                         const typename MyClass<K, V>::MyMapType& map) {
    for (auto p : map)
        stream << p.first << std::endl;
    return stream;
}


int main(int argc, char const* argv[]) {
    MyClass<std::string, int> c;
    c.mymap["a"] = 1;
    c.mymap["b"] = 2;
    std::cout << c.mymap << std::endl;
    return 0;
}

在您的示例中,您甚至无法访问MyClass<...>中的任何内容。甚至没有远程理由声明它friend

BTW。:std::endl也会刷新流。考虑在运营商中使用"\n"