X的放大与缩小(运算符重载)

1.题目概述

X字母可以放大和缩小,变为n行X(n=1,3,5,7,9,…,21)。

现假设一个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时,放大不起作用。

2.代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/*例如,3行x图案如下:
xxx
x
xxx */

#include <iostream>
using namespace std;

class CXGraph
{
char** x;
int N;
public:
CXGraph(){}
CXGraph(int n)
{
N = n;
x = new char*[n];
for (int i = 0; i < n; ++i)
{
x[i] = new char[n];
}

int temp = n;
for (int i = 0; i < ((n+1)/2); i++)
{
for (int j = 0; j < i; j++)
{
x[i][j] = ' ';
x[n - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++)
{
x[i][j] = 'X';
x[n - i - 1][j] = 'X';
}
temp --;
}
}

CXGraph(const CXGraph& tmp)
{
N = tmp.N;
x = new char* [N];
for (int i = 0; i < N; ++i)
{
x[i] = new char[N];
}


for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
x[i][j] = tmp.x[i][j];
}
}

}
~CXGraph()
{
for (int i = 0; i < N; i++)
{
delete []x[i];
}
delete[]x;
}

//这里规范来说,应该全部加const,但是当时编译时出了问题,发现把const去掉就好了
//结尾贴出改进方法--作为类成员函数重载
friend CXGraph operator++(CXGraph& a);//前缀运算++a
friend CXGraph operator++(CXGraph& a, int b);//后缀运算a++
friend CXGraph operator--(CXGraph& a);
friend CXGraph operator--(CXGraph& a, int b);
friend ostream& operator<<(ostream& os, const CXGraph& x);
CXGraph& operator=(const CXGraph& a);
};

CXGraph operator++(CXGraph& a)
{
if (a.N == 21) return a;
for (int i = 0; i < a.N; ++i)
delete[] a.x[i];
delete[] a.x;
a.N += 2;
a.x = new char* [a.N];
for (int i = 0; i < a.N; ++i)
a.x[i] = new char[a.N];
int temp = a.N;
for (int i = 0; i < ((a.N + 1) / 2); i++)
{
for (int j = 0; j < i; j++)
{
a.x[i][j] = ' ';
a.x[a.N - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++)
{
a.x[i][j] = 'X';
a.x[a.N - i - 1][j] = 'X';
}
temp--;
}
return a;
}

CXGraph operator++(CXGraph& a, int b)
{
if (a.N == 21) return a;
CXGraph t(a);
for (int i = 0; i < a.N; ++i)
{
delete[] a.x[i];
}
delete[] a.x;

a.N += 2;
a.x = new char* [a.N];
for (int i = 0; i < a.N; ++i)
{
a.x[i] = new char[a.N];
}

int temp = a.N;
for (int i = 0; i < ((a.N + 1) / 2); i++)
{
for (int j = 0; j < i; j++)
{
a.x[i][j] = ' ';
a.x[a.N - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++)
{
a.x[i][j] = 'X';
a.x[a.N - i - 1][j] = 'X';
}
temp--;
}
return t;
}

CXGraph operator--(CXGraph& a)
{
if (a.N == 1) return a;
for (int i = 0; i < a.N; ++i)
{
delete[] a.x[i];
}
delete[] a.x;

a.N -= 2;
a.x = new char* [a.N];
for (int i = 0; i < a.N; ++i)
a.x[i] = new char[a.N];
int temp = a.N;
for (int i = 0; i < ((a.N + 1) / 2); i++)
{
for (int j = 0; j < i; j++)
{
a.x[i][j] = ' ';
a.x[a.N - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++)
{
a.x[i][j] = 'X';
a.x[a.N - i - 1][j] = 'X';
}
temp--;
}
return a;
}

CXGraph operator--(CXGraph& a, int b)
{
if (a.N == 1) return a;
CXGraph t(a.N);
for (int i = 0; i < a.N; ++i)
{
delete[] a.x[i];
}
delete[] a.x;

a.N -= 2;
int temp = a.N;
a.x = new char* [a.N];
for (int i = 0; i < a.N; ++i)
a.x[i] = new char[a.N];

for (int i = 0; i < ((a.N + 1) / 2); i++)
{
for (int j = 0; j < i; j++)
{
a.x[i][j] = ' ';
a.x[a.N - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++)
{
a.x[i][j] = 'X';
a.x[a.N - i - 1][j] = 'X';
}
temp--;
}

return t;
}

ostream& operator<<(ostream& os, const CXGraph& x)
{
int t = x.N;
for (int i = 0; i < (x.N+1)/2; i++)
{
for (int j = 0; j < t; j++)
{
cout << x.x[i][j] ;
}
cout << endl;
t--;
}

t += 2;
for (int i = (x.N + 1) / 2; i < x.N; i++)
{
for (int j = 0; j < t; j++)
{
cout << x.x[i][j];
}
cout << endl;
t++;
}

return os;
}

CXGraph& CXGraph::operator=(const CXGraph& a)
{
for (int i = 0; i < N; ++i) {
delete[] x[i];
}
delete[] x;

N = a.N;
x = new char* [N];
for (int i = 0; i < N; ++i) {
x[i] = new char[N];
for (int j = 0; j < N; ++j) {
x[i][j] = a.x[i][j];
}
}

return *this;
}

int main()
{
int t, n;
string command;
cin >> n;
CXGraph 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;
}

3.要点

1.运算符重载的两种形式

  • 类成员函数(有this指针)ps:二元运算符以成员函数形式重载,左操作数必须为类对象,目标对象作为左操作数

  • 友元函数(无this指针)

  • 一般单目运算符最好重载为类的成员函数,双目运算符则重载为类的友元函数

  • 一些双目运算符不能重载为友元函数:=、()、[]、->

  • 若需要修改对象的状态,最好选择成员函数重载

2.改进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
CXGraph& operator++()//++a
{
if (N == 21) return *this;

// 释放原有内存
for (int i = 0; i < N; ++i)
delete[] x[i];
delete[] x;

N += 2;
x = new char* [N];
for (int i = 0; i < N; ++i)
x[i] = new char[N];

int temp = N;
for (int i = 0; i < ((N + 1) / 2); i++) {
for (int j = 0; j < i; j++) {
x[i][j] = ' ';
x[N - i - 1][j] = ' ';
}
for (int j = i; j < temp; j++) {
x[i][j] = 'X';
x[N - i - 1][j] = 'X';
}
temp--;
}

return *this;
}

!!!CXGraph CXGraph::operator++(int)【a++】返回的是局部变量,而返回局部变量(临时对象)的引用属于悬空引用,不正确。所以与前置加加不同,这里不返回引用。

3.关于<<和>>的运算符重载

1
2
friend ostream& operator<<(ostream& os,const CXGraph& t);
friend istream& operator>>(istream& is,CXGraph& t);