Essential C++学习记录&笔记整理30(重载iostream运算符)

这一节解决了我前面遇到的操作符重载的问题而不能显示类对象的数据,以及输出的显示顺序问题。
好的让我们开始总结这一节所学

  • 为什么有要重载iostream运算符?
    因为我们想对某个类对象进行读写操作。不重载iostream类运算符直接cout<<类对象<cin>>类对象;编译器会报错

目录

    • 重载ostream运算符
    • 重载istream运算符
    • 报错信息,学习一下

重载ostream运算符

直接cout<<类对象<编译器会报错,所以我们要有个重载的<<运算符函数,比如:

ostream& operator<<(ostream &os,const Triangular &rhs)
{
	os<<"("<<rhs.beg_pos()<<","
	  <<rhs.legnth()<<")";
	  rhs.display(rhs.length(),rhs.beg_pos(),os);
	  return os;
	  //传入重载运算符函数的ostream对象又被原封不动地返回
}

这就是重载的<<运算符,内部的实现是输出什么东西,这个由你自己设定,就按照如代码所示的设定仿写就可以。ostream对象没有被声明为const,是因为每一次输出操作都会更改ostream对象的内部状态(查资料可详细了解如何更改ostream对象的内部状态
被输出的对象被声明为const是可以的。
我们使用了&,是基于效率考虑而非为了修改其对象内容。

  • 好的,定义了重载<<运算符的函数,现在让我们定义并初始化一个类对象,然后输出这个类对象的东西(相关数据)
Triangular tri(6,3);
cout<<tri<<endl;

输出结果:(3,6) 6 10 15 21 28 36

  • 你可能有疑问,为什么不把输出(<<)运算符设计为一个成员函数呢?(我没有这个疑问,我本来就觉得重载<<运算符应该服务于所有类的类对象)
  • 因为如果把<<运算符函数设计为成员函数,那么<<的左操作数就必须是和<<运算符函数属于同一个类的类对象。我举个例子,比如<<运算符被设计为tri类对象的类成员函数,那么tri类对象就得放在<<运算符的左侧tri<奇不奇怪,适应吗?那所以把<<运算符函数设计成非成员函数的函数多好啊!

重载istream运算符

  • 和ostream运算符一样,你可以在重载运算符函数内部设定你要读取什么,举个例子:
istream& operator>>(istream &is,Triangular &rhs)
{
	char ch1,ch2;//定义两个字符用来规定
	//>>运算符后的输入格式,像scanf函数里可规定输入格式那样
	int bp,len;//起始位置和数列长度的定义
	is>>ch1>>bp>>ch2>>len;
	//假设输入为(3,6) 6 10 15 21 28 36
	//那么ch1=='(',bp==3,ch2==',',len==6。
	rhs.beg)pos(bp);
	rhs.length(len);
	rhs.next_reset();
	//输入的数据对应传给传进来的类对象(rhs)的数据成员。
	return is;
	//传入重载运算符函数的istream对象又被原封不动地返回
}

现在,让我们把最后那点问题给解决掉吧!

main.cpp
#include
#include
#include"Triangular.h"
using namespace std;
int sum(const Triangular &trian);//得在这有个声明,因为该函数在别的文件里定义的,否则报错
//error: 'sum' was not declared in this scope|
ostream&
operator<<( ostream &os, const Triangular &rhs );//得在这有个声明,因为该函数在别的文件里定义的,否则报错
//error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream}' and 'Triangular')|
int main()
{
	Triangular tri(4);//定义类对象并调用该类的构造函数
	//(该类的构造函数声明或定义时
	//已经给函数参数表里的每个参数提供了默认参数值
	cout<<tri<<" --sum of elemnts:"
	//注意一开始输出了类对象的内容!关于类对象的内容我一会儿
	//会把输出结果给你写上!
		<<sum(tri)<<endl;//sum()函数的返回值为int,当然可以插进
		//cout输出流里。
	Triangular tri2(4,3);
	cout<<tri2<<" --sum of elements:"
		<<sum(tri2)<<endl;
	Triangular tri3(4,8);
	cout<<tri3<<" --sum of elements:"
		<<sum(tri3)<<endl;
    return 0;
}
Triangular.cpp文件
#include
#include
#include"Triangular.h"
using namespace std;
static vector<int> _elems;//想用vector不光包含vector头文件还要包含iostream头文件及命名空间std
//而且这里声明了静态类成员,类头文件里就不要声明静态类成员了!否则报错!undefined reference to `Triangular::_elems'|
Triangular::Triangular( const Triangular &rhs )
	: _length ( rhs._length  ),
      _beg_pos( rhs._beg_pos ),
	  _next( rhs._next )
{}//Triangular( const Triangular& );类构造函数的定义,不加这个程序报错undefined reference to `Triangular::Triangular(int, int)'|
Triangular::Triangular( int len, int beg_pos )
    : _length( len > 0 ? len : 1 ),
      _beg_pos( beg_pos > 0 ? beg_pos : 1 )
{
	_next = _beg_pos;

	int elem_cnt = _beg_pos + _length;
    if ( _elems.size() < elem_cnt )
         gen_elements( elem_cnt );
}
void Triangular::
gen_elements( int length )
{
    if ( length < 0 || length > _max_elems ){
        cerr << "Triangular Sequence: oops: invalid size: "
             << length << " -- max size is "
             << _max_elems << endl;
        return;
	}

    if ( _elems.size() < length )
	{
		int ix = _elems.size() ? _elems.size()+1 : 1;
		for ( ; ix <= length; ++ix )
			  _elems.push_back( ix*(ix+1)/2 );
	}
}

bool Triangular::
next( int &value ) const
{
	if ( ! _next )
        return false;

	if ( _next < _beg_pos + _length ) {
        // error: modifying _next
		  value = _elems[ _next++ ];
        return true;
	}
	_next = 0; // error: modifying _next
	return false;
}
ostream&
operator<<( ostream &os, const Triangular &rhs )
{
    os << "( "
	    << rhs.beg_pos() << " , "
	    << rhs.length()  << " ) ";

    //rhs.display( rhs.length(), rhs.beg_pos(), os );
    return os;
}
//重载运算符函数的定义放在了要用到的文件
int sum(const Triangular &trian)
{
	if(!trian.length())
	{
		return 0;
	}//类对象的长度这个数据成员是0的话,退出sum函数体
	int val,sum=0;
	trian.next_reset();
	while(trian.next(val))
	{
		sum+=val;
	}
	return sum;
}
Triangular.h文件
//不需要#ifndef和#endif
#include
#include
using namespace std;
class Triangular{
public:
	bool next(int &val)const;
	void next_reset()const
	{
		_next=_beg_pos-1;
	}
    int length()  const { return _length;  }
    int beg_pos() const { return _beg_pos; }
	Triangular( int len = 1, int bp = 1 );
	Triangular( const Triangular& );
	//void display( int length, int beg_pos, ostream &os );
    void gen_elements( int length );
	//...
private:
	mutable int _next;
	int _beg_pos;
	int _length;
	enum { _max_elems = 1024 };
};

程序运行结果:
Essential C++学习记录&笔记整理30(重载iostream运算符)_第1张图片
至少(1,4)(3,4)这种逆序输出我知道是为什么了(sum的输出实际上无关紧要,因为我在全部的源代码上试了输出也有问题!),是因为重载运算符函数定义里os<<。。。。<<…<<…的顺序是这么安排的,先输出起始位置再输出长度
随后我测试了重载istream运算符。这里只给出新增代码

//main.cpp
	//...
	istream& operator>>( istream &is, Triangular &rhs );
	//重载>>运算符函数声明
	Triangular tri(6,3);
    cout<<tri<<'\n';
    Triangular tri2;
    cin>>tri2;
    cout<<tri2;
    //...
//Triangular.cpp
//...
istream&
operator>>( istream &is, Triangular &rhs )
{
	char ch1, ch2;
	int bp, len;

   // given the input: ( 3 , 6 ) 6, 10, 15, 21, 28, 36
   // ch1 == ‘(’, bp == 3, ch2 == ‘,’, len == 6
	is >> ch1 >> bp >> ch2 >> len;

   rhs.beg_pos( bp );
   rhs.length( len );
   rhs.next_reset();

	return is;
}
//...
//Triangular.h
class Triangular{
public:
	//...
	void length( int nlen ) { _length = nlen; }
    void beg_pos( int npos ){ _beg_pos = npos; }//.cpp文件里用到了这俩重载函数(rhs.beg_pos( bp ); rhs.length( len );)
   //所以这里得声明。否则编译器报错error: no matching function for call to 'Triangular::length(int&)'|

输出结果在第一行和第三行,我输入了(4,10)(必须按照重载<<运算符函数里写的规定的格式来输入!)
Essential C++学习记录&笔记整理30(重载iostream运算符)_第2张图片

报错信息,学习一下

①类构造函数只声明不定义,编译器报错。undefined reference to `Triangular::Triangular(int, int)’|
②/想用vector不光包含vector头文件还要包含iostream头文件及命名空间std否则编译器报错
③而且这里声明了静态类成员,类头文件里就不要声明静态类成员了!否则报错!undefined reference to Triangular::_elems’|
④ostream&
operator<<( ostream &os, const Triangular &rhs );得在主函数里有个声明,因为该函数在类的头文件的程序代码文件里定义的,否则报错

error: no match for 'operator<<' 
(operand types are 'std::ostream {aka std::basic_ostream}' and 'Triangular')|

int sum(const Triangular &trian);//得在主函数里有个声明,因为该函数在类的头文件的程序代码文件里定义的,否则报错
//error: ‘sum’ was not declared in this scope|

⑥.cpp文件里用到了重载函数(两个)(rhs.beg_pos( bp ); rhs.length( len );)
所以其所属头文件(类头文件)得声明(声明在类的public:里)。否则编译器报错:error: no matching function for call to ‘Triangular::length(int&)’| 总结一下,反正就是函数声明和定义都得有,否则就出现了error: no matching function for call to。。。这样的编译器报错信息

你可能感兴趣的:(C++)