如何重载运算符<<为类成员?
How to overload operator<< for a class member?
假设我想打印一个类成员,我试图重载该成员的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的派生?
它只需要在类之外:
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
。
您的原始示例不起作用,因为您没有MyClass类型的参数,所以在MyClass中找不到函数。只有在类外部声明友元函数或者友元函数具有类类型的参数时,才能在类外部找到友元函数。
很抱歉,@Vaughn Cato,但问题与friend
声明无关。无论如何都没有必要,因此应该避免。
@茶洛:"课堂朋友功能"应该是什么?这没有任何意义。
编译器错误消息在此处具有误导性。找不到函数,因为它不存在。您已经定义了一个操作符,左边是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
。
顺便说一下:std::endl
还刷新流。考虑在运算符内部使用"n"
。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 助记符和指向成员语法的指针
- 用于访问容器<T>数据成员的正确 API
- 内置函数可查看CPP中的成员变量
- 是否可以初始化不可复制类型的成员变量(或基类)
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 嵌套在类中时无法设置成员数据
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 将函数类成员映射到类本身内部
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 将Ref对象作为类成员
- 将包含C样式数组的对象初始化为成员变量(C++)
- 静态数据成员的问题-修复链接错误会导致编译器错误
- 将公共但非静态的成员函数与ALGLIB集成
- C++分离成员流重载<<
- 重载运算符<<输出地址而不是数据成员