面向对象程序设计|理解++i和i++

首先我们从最简单的整型运算来理解前++和后++:

面向对象程序设计|理解++i和i++_第1张图片

 将a=10再赋值20意味着(a=10)返回的是a的空间,又把这个20赋值给这个空间的内存,最后a=20;

++(++a)意味着++a返回的是空间(引用),可以继续作++的调用,引用使得++a是可修改的左值;

又由于后置++的优先级大于前置++,因此20行和21行的本质一样,会出现报错。因为a++操作通过临时量返回其值,该值是一个常量,因此不能被修改(不是左值),而后缀++需要对左值进行操作,所以会引起编译错误。
所谓的左值,说通俗一点就是可以被修改和引用的值,左值可以取地址。与之相对的就是右值。在使用时,左值可以作为右值,但右值不能作为左值。

以两道例题为例:

题目一:X的放大与缩小(运算符重载)

题目描述:

X字母可以放大和缩小,变为n行X(n=1,3,5,7,9,...,21)。例如,3行x图案如下:

面向对象程序设计|理解++i和i++_第2张图片

现假设一个n行(n>0,奇数)X图案,遥控器可以控制X图案的放大与缩小。遥控器有5个按键,1)show,显示当前X图案;2)show++, 显示当前X图案,再放大图案,n+2;3)++show,先放大图案,n+2,再显示图案;4)show--,显示当前X图案,再缩小图案,n-2;5)--show,先缩小图案,n-2,再显示图案。假设X图案的放大和缩小在1-21之间。n=1时,缩小不起作用,n=21时,放大不起作用。

用类CXGraph表示X图案及其放大、缩小、显示。主函数模拟遥控器,代码如下,不可修改。请补充CXGraph类的定义和实现。

面向对象程序设计|理解++i和i++_第3张图片

 输入要求:

第一行n,大于0的奇数,X图案的初始大小。

第二行,操作次数

每个操作一行,为show、show++、show--、--show、++show之一,具体操作含义见题目。

输出要求:

对每个操作,输出对应的X图案。

输入样例:

3
5
show
show++
show++
++show
--show

输出样例:

XXX
 X
XXX
 
XXX
 X
XXX
 
XXXXX
 XXX
  X
 XXX
XXXXX
 
XXXXXXXXX
 XXXXXXX
  XXXXX
   XXX
    X
   XXX
  XXXXX
 XXXXXXX
XXXXXXXXX
 
XXXXXXX
 XXXXX
  XXX
   X
  XXX
 XXXXX
XXXXXXX

代码示例:

#include
#include
#include
#include 
#include
#include
using namespace std;
 
class XGraph
{
private:
	int n;
public:
	XGraph(int nn) :n(nn) {}
	XGraph(XGraph& rhs)
	{
		n = rhs.n;
	}
	XGraph& operator++()//前置++,返回的是引用;前置用引用则是为了不产生临时变量,可以减少内存的消耗。
	{
		if (this->n <= 19)
		{
			this->n += 2;
		}
		return *this;
	}
	XGraph operator++(int)//后置++,返回的是临时对象,因为后置的时候原来的对象已经被++改变了。
	{					  //后置的函数的声明里面参数列表中比前置多了一个int,这里的int其实是作为区分前后置的标志,在函数体里面并没有直接地用到。
		XGraph temp = *this;
		if (this->n <= 19)
		{
			this->n += 2;
		}
		return temp;
	}
	XGraph& operator--()//原理与++或--相同
	{
		if (this->n >= 3)
		{
			this->n -= 2;
		}
		return *this;
	}
	XGraph operator--(int)
	{
		XGraph temp = *this;
		if (this->n >= 3)
		{
			this->n -= 2;
		}
		return temp;
	}
	friend ostream& operator<<(ostream& out, const XGraph& rhs);//输出运算符重载,记住特定的格式
};
 
ostream& operator<<(ostream& out, const XGraph& rhs)
{
	for (int i = 0; i < (rhs.n + 1) / 2; i++)
	{
		for (int j = 0; j < i; j++)
		{
			cout << " ";
		}
		for (int j = i; j < rhs.n - i; j++)
		{
			cout << "X";
		}
		cout << endl;
	}
	for (int i = (rhs.n + 1) / 2; i < rhs.n; i++)
	{
		for (int j = rhs.n - 1 - i; j > 0; j--)
		{
			cout << " ";
		}
		for (int j = rhs.n - 1 - i; j <= i; j++)
		{
			cout << "X";
		}
		cout << endl;
	}
	return out;
}
 
 
int main()
{
	int t, n;
	string command;
	cin >> n;
	XGraph xGraph(n);
	cin >> t;
	while (t--)
	{
		cin >> command;
		if (command == "show++")
		{
			cout << xGraph++ << endl;
		}
		else if (command == "++show")
		{
			cout << ++xGraph << endl;
		}
		else if (command == "show--")
		{
			cout << xGraph-- << endl;
		}
		else if (command == "--show")
		{
			cout << --xGraph << endl;
		}
		else if (command == "show")
			cout << xGraph << endl;
 
	}
	return 0;
}

前置++,返回的是引用;前置用引用则是为了不产生临时变量,可以减少内存的消耗。

后置++,返回的是临时对象,因为后置的时候原来的对象已经被++改变了。

后置的函数的声明里面参数列表中比前置多了一个int,这里的int其实是作为区分前后置的标志,在函数体里面并没有直接地用到。

再以整数运算为例,如果是 cout << a++; 的话,是先输出a的值,a再加1。当运行后置++的时候,我们先备份当前对象的值,然后在返回前把它做了加一的动作,然后返回备份的值。因为备份的值是局部对象,因此不能返回局部对象的引用,引用的话就是说你出了这个函数,空间必须还在,但局部对象在函数结束后就被析构了,所以只能返回对象。

题目二:三维点坐标平移(增量运算符重载)

题目描述:

定义一个三维点Point类,利用友元函数重载"++"和"--"运算符,并区分这两种运算符的前置和后置运算。

++表示x\y\z坐标都+1,--表示x\y\z坐标都-1

请完成以下程序填空

输入要求:

只有一行输入,输入三个整数,表示点的x/y/z坐标

输出要求:

由主函数自行输出

输入样例:

10 20 30

输出样例:

x=11 y=21 z=31
x=10 y=20 z=30
x=11 y=21 z=31
x=11 y=21 z=31
x=9 y=19 z=29
x=10 y=20 z=30
x=9 y=19 z=29
x=9 y=19 z=29

代码框架:

#include 
using namespace std;

class Point;
Point operator -- (Point & );
Point operator -- (Point &, int);

class Point {
private:
	int x, y, z;
public:
	Point(int tx=0, int ty=0, int tz=0 )
	{	x = tx, y = ty, z = tz;	}
	Point operator ++ ();
	Point operator ++ (int);
	friend Point operator -- (Point & );
	friend Point operator -- (Point &, int);
	void print();
};
//完成以下填空
/********** Write your code here! **********/




/*******************************************/
int main()
{	int tx, ty, tz;
	cin>>tx>>ty>>tz;
	Point p0(tx, ty, tz); //原值保存在p0
	Point p1, p2;	//临时赋值进行增量运算

	//第1行输出
	p1 = p0;
	p1++;;
	p1.print();
	//第2行输出
	p1 = p0;
	p2 = p1++;
	p2.print();
	//第3、4行输出,前置++
	p1 = p0;
	(++p1).print();
	p1.print();
	//第5、6行输出,后置--
	p1 = p0;
	p1--;
	p1.print();
	p0.print();
	//第7、8行输出,前置--
	p1 = p0;
	(--p1).print();
	p1.print();

	return 0;
}

代码示例:

#include 
using namespace std;

class Point;
Point operator -- (Point & );
Point operator -- (Point &, int);

class Point {
private:
	int x, y, z;
public:
	Point(int tx=0, int ty=0, int tz=0 )
	{	x = tx, y = ty, z = tz;	}
	Point operator ++ ();
	Point operator ++ (int);
	friend Point operator -- (Point & );
	friend Point operator -- (Point &, int);
	void print();
};
//完成以下填空
Point Point::operator++()
{
	x++;
	y++;
	z++;
	return *this;
}

Point Point::operator++(int)
{
	Point temp = *this;
	x++;
	y++;
	z++;
	return temp;
}
Point operator -- (Point& rhs)
{

	rhs.x--;
	rhs.y--;
	rhs.z--;
	return rhs;
}
Point operator -- (Point& rhs, int n)
{
	Point temp = rhs;
	rhs.x--;
	rhs.y--;
	rhs.z--;
	return temp;
}

void Point::print()
{
	cout << "x=" << x << " y=" << y << " z=" << z << endl;
}
int main()
{	int tx, ty, tz;
	cin>>tx>>ty>>tz;
	Point p0(tx, ty, tz); //原值保存在p0
	Point p1, p2;	//临时赋值进行增量运算

	//第1行输出
	p1 = p0;
	p1++;;
	p1.print();
	//第2行输出
	p1 = p0;
	p2 = p1++;
	p2.print();
	//第3、4行输出,前置++
	p1 = p0;
	(++p1).print();
	p1.print();
	//第5、6行输出,后置--
	p1 = p0;
	p1--;
	p1.print();
	p0.print();
	//第7、8行输出,前置--
	p1 = p0;
	(--p1).print();
	p1.print();

	return 0;
}

我们按照要求完成代码,同时用另一种方法完成代码,分别成为代码一、代码二。

代码二:

#include 
using namespace std;

class Point;

class Point {
private:
	int x, y, z;
public:
	Point(int tx = 0, int ty = 0, int tz = 0)
	{
		x = tx, y = ty, z = tz;
	}
	Point& operator ++ ();
	Point operator ++ (int);
	Point& operator -- ();
	Point operator -- (int);
	void print();
};
//完成以下填空
Point& Point::operator++()
{
	x++;
	y++;
	z++;
	return *this;
}

Point Point::operator++(int)
{
	Point temp = *this;
	x++;
	y++;
	z++;
	return temp;
}
Point& Point::operator -- ()
{

	x--;
	y--;
	z--;
	return *this;
}
Point Point::operator -- (int)
{
	Point temp = *this;
	x--;
	y--;
	z--;
	return temp;
}

void Point::print()
{
	cout << "x=" << x << " y=" << y << " z=" << z << endl;
}
int main()
{
	int tx, ty, tz;
	cin >> tx >> ty >> tz;
	Point p0(tx, ty, tz); //原值保存在p0
	Point p1, p2;	//临时赋值进行增量运算

	//第1行输出
	p1 = p0;
	p1++;;
	p1.print();
	//第2行输出
	p1 = p0;
	p2 = p1++;
	p2.print();
	//第3、4行输出,前置++
	p1 = p0;
	(++p1).print();
	p1.print();
	//第5、6行输出,后置--
	p1 = p0;
	p1--;
	p1.print();
	p0.print();
	//第7、8行输出,前置--
	p1 = p0;
	(--p1).print();
	p1.print();


	return 0;
}

我们会发现对代码一,有这样的错误:

面向对象程序设计|理解++i和i++_第4张图片

 而代码二则不会产生问题:

面向对象程序设计|理解++i和i++_第5张图片

其本质原因是:代码一第一个前--返回的是对象,再次前--,是在临时对象上减而不是在原对象,返回对象做对象的备份和原对象不是一个空间。

你可能感兴趣的:(Simple,C++,开发语言,C++,算法)