为什么 C++ 编译器不为 class 提供重载的插入器和提取器函数?
Why C++ compiler doesn't provide overloaded inserter & extractor functions for class?
考虑以下程序。
#include <iostream>
using std::ostream;
using std::cout;
using std::istream;
using std::cin;
class three_d {
int i,j,k;
public:
three_d(int a,int b,int c) : i(a),j(b),k(c)
{ }
//friend ostream& operator << (ostream&,const three_d&);
//friend istream& operator >> (istream&,three_d&);
};
/*ostream& operator << (ostream& o,const three_d& t) {
o<<t.i<<", ";
o<<t.j<<", ";
o<<t.k<<"\n";
return o;
}
istream& operator >> (istream& stream,three_d &t) {
cout<<"Enter x,y,z values";
stream>>t.i>>t.j>>t.k;
return stream;
}*/
int main() {
three_d a(1,2,3),b(4,5,6),c(7,8,9);
cout<<a<<b<<c;
cin>>a;
cout<<a;
}
我特意注释掉了重载的 >> & << 运算符函数定义,编译器给出了以下错误消息
*[Error] no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'three_d')
[Error] no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'three_d')*
默认情况下,即使是空 class 如果程序员不提供,C++ 编译器会自动提供以下内容。
1) 构造函数
2) 析构函数
3) 复制构造函数
4) =(赋值)运算符
那么为什么 >> & << 运算符必须由程序员显式重载才能使用用户定义的类型 (class)?如果默认情况下编译器也为用户定义的类型提供重载的 >> & << 运算符函数,那不是很好吗?这不是减少了编写代码所需的代码并减轻了程序员的负担吗?
Then why >> & << operators has to be explicitly overloaded by programmer to work with user defined types(class)?
None 你列为默认的提供了序列化或反序列化,这是两个非常复杂的问题,通常要解决。
您列出的所有四个事物都可以在语义上重新排序它们的操作,但是 serialization/deserialization 不能。
另外序列化数据应该是什么格式?二进制还是文本?数据字段之间应该使用什么分隔符?数据字段应该命名还是简单排序?
最终 none 最初的四个可能会失败,但是 istream
可能会由于多种原因而失败。当它失败时你会怎么做?您 return 是部分初始化和部分默认的 class 还是抛出异常?
并不是说这一系列问题无法回答,而是答案取决于您的其余代码在做什么,因此不可能有笼统的答案。许多地方希望能够为后者保存数据,因此紧凑的二进制表示很好。其他地方希望能够方便地向用户展示一个数据结构,这就需要一个文本表示。
此外,到目前为止,反对这个想法的最大因素是添加功能的固有成本。 This is answer on that topic(有一些关于该主题的更全面的博客文章,但我没有 link 方便的抱歉)。
考虑以下程序。
#include <iostream>
using std::ostream;
using std::cout;
using std::istream;
using std::cin;
class three_d {
int i,j,k;
public:
three_d(int a,int b,int c) : i(a),j(b),k(c)
{ }
//friend ostream& operator << (ostream&,const three_d&);
//friend istream& operator >> (istream&,three_d&);
};
/*ostream& operator << (ostream& o,const three_d& t) {
o<<t.i<<", ";
o<<t.j<<", ";
o<<t.k<<"\n";
return o;
}
istream& operator >> (istream& stream,three_d &t) {
cout<<"Enter x,y,z values";
stream>>t.i>>t.j>>t.k;
return stream;
}*/
int main() {
three_d a(1,2,3),b(4,5,6),c(7,8,9);
cout<<a<<b<<c;
cin>>a;
cout<<a;
}
我特意注释掉了重载的 >> & << 运算符函数定义,编译器给出了以下错误消息
*[Error] no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and 'three_d')
[Error] no match for 'operator>>' (operand types are 'std::istream {aka std::basic_istream<char>}' and 'three_d')*
默认情况下,即使是空 class 如果程序员不提供,C++ 编译器会自动提供以下内容。
1) 构造函数
2) 析构函数
3) 复制构造函数
4) =(赋值)运算符
那么为什么 >> & << 运算符必须由程序员显式重载才能使用用户定义的类型 (class)?如果默认情况下编译器也为用户定义的类型提供重载的 >> & << 运算符函数,那不是很好吗?这不是减少了编写代码所需的代码并减轻了程序员的负担吗?
Then why >> & << operators has to be explicitly overloaded by programmer to work with user defined types(class)?
None 你列为默认的提供了序列化或反序列化,这是两个非常复杂的问题,通常要解决。
您列出的所有四个事物都可以在语义上重新排序它们的操作,但是 serialization/deserialization 不能。
另外序列化数据应该是什么格式?二进制还是文本?数据字段之间应该使用什么分隔符?数据字段应该命名还是简单排序?
最终 none 最初的四个可能会失败,但是 istream
可能会由于多种原因而失败。当它失败时你会怎么做?您 return 是部分初始化和部分默认的 class 还是抛出异常?
并不是说这一系列问题无法回答,而是答案取决于您的其余代码在做什么,因此不可能有笼统的答案。许多地方希望能够为后者保存数据,因此紧凑的二进制表示很好。其他地方希望能够方便地向用户展示一个数据结构,这就需要一个文本表示。
此外,到目前为止,反对这个想法的最大因素是添加功能的固有成本。 This is answer on that topic(有一些关于该主题的更全面的博客文章,但我没有 link 方便的抱歉)。