BlueClue's Tech Blog

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

问题
《C++沉思录:Ruminations on C++》由Picture类(负责文字信息的存储)、frame函数(创建新Picture并加框存储)、'|'运算符重载(创建新Picture,并将两幅文字作横向合并存储)、'&'运算符重载(创建新Picture,并将两幅文字做纵向合并存储)完成的方案,这种方法的缺点是:

  • 复制图像就要复制字符,而且把一副小图像并到大图像的过程中,也要复制其内部字符
  • 可能花费不少内存来存储空格,如果图像中某一行明显比其他各行长得多,那么这一开销就不容忽视了
  • 会丢掉所有图像内部结构信息,如果想写一个去掉边框的函数,我们无法区分真正的边框和字符

作者认为上述这些缺点是因为我们实现了Picture类来存储一个图像的“表象”,却没有存储其结构,本书第10章则利用了类继承和句柄类来解决上面得问题:一则可以将我们使用继承的实现细节隐藏起来,二则可以省去用户处理内存管理的麻烦,而提供给用户的接口不变(class Picture、frame()、|、&)。

解决内存问题
对于内存浪费的举个简单的例子就可以说明: 

1 char*init[]= {"Paris","in the","Spring"};
2 Picture p1(init,3);
3 Picture p2 = frame(p2);

 用第9章的代码,运行起来,在调试器里我们看到(注意p1、p2的data里面的内容)——

"Paris in the Spring"这段文字被复制后保存在两块内存中,在实际运行中,p2没有理由去复制p1的全部内容,看过前几章节的朋友可能会想到一个处理方法,没错,句柄类!
句柄类P_Node具有引用计数功能,并允许Picture类的访问,即:

1 class P_Node{
2 friend class Picture;
3  protected:
4 int use;
5 };

 解决保存内部结构方案

1 class String_Pic: public P_Node{}; //直接由字符串数组生成的图像
2  class Frame_Pic: public P_Node{}; //给其他图像加边框而形成的图像
3  class VCat_Pic: public P_Node{}; //两幅图像横向连接所得的图像
4 class HCat_Pic: public P_Node{}; //两幅图像纵向连接所得的图像

类继承树的方案也解决占用内存的问题——String_Pic用来存储文字内容,其他三个类只是引用它的内容,在打印的时候做加框和连接处理,如此用来我们再看第一个例子的运行情况:

 

类图

代码(被折叠)

 

class Picture
1 #ifndef PICTURE_HDL_H
2 #define PICTURE_HDL_H
3
4 #include <iostream>
5
6 usingnamespace std;
7
8 /*****类定义************************************************************************/
9 class P_Node;
10 //Picture类定义
11 class Picture
12 {
13 friend Picture frame(const Picture&); //加框
14 friend Picture operator&(const Picture&, const Picture&); //纵向合并
15 friend Picture operator|(const Picture&, const Picture&); //横向合并
16 friend ostream&operator<< (ostream& o, const Picture& p);//输出运算符重载
17 friend staticvoid pad(ostream& os, int x, int y);
18 friend class String_pic;
19 friend class Frame_Pic;
20 friend class Hcat_Pic;
21 friend class Vcat_pic;
22 public:
23 Picture(constchar*const*, int);
24 Picture(const Picture& );
25 ~Picture();
26 Picture&operator=(const Picture&);
27 private:
28 Picture(P_Node* p_node): p(p_node){};
29 int height() const;
30 int width() const;
31 void display(ostream&, int, int)const;
32 P_Node* p;
33 };
34
35 //句柄类
36 class P_Node
37 {
38 friend class Picture;
39 protected:
40 P_Node():use(1){};
41 virtual~P_Node(){};
42 virtualint height() const=0;
43 virtualint width() const=0;
44 virtualvoid display(ostream&, int, int) const=0;
45 int max(int x,int y) const{ return (x > y ? x : y);};
46 private:
47 int use;
48 };
49 //文字图像句柄类
50 class String_Pic: public P_Node
51 {
52 friend class Picture;
53 String_Pic(constchar*const*, int);
54 ~String_Pic();
55 int height() const;
56 int width() const;
57 void display(ostream&, int ,int) const;
58 char** data;
59 int size;
60 };
61 //加框图像句柄类
62 class Frame_Pic: public P_Node
63 {
64 friend Picture frame(const Picture&);
65 Frame_Pic(const Picture& pic):p(pic){};
66 int height() const { return p.height() +2;};
67 int width() const { return p.width() +2;};
68 void display(ostream&, int ,int) const;
69 Picture p;
70 };
71 //纵向合并图像句柄类
72 class Vcat_pic: public P_Node
73 {
74 friend Picture operator&(const Picture&, const Picture&);
75 Vcat_pic(const Picture& t, const Picture& b):top(t),bottom(b){};
76 int height() const{ return top.height() + bottom.height();};
77 int width() const{ return max(top.width(), bottom.width());};
78 void display(ostream&, int ,int) const;
79 Picture top, bottom;
80 };
81 //横向合并图像句柄类
82 class Hcat_Pic: public P_Node
83 {
84 friend Picture operator|(const Picture&, const Picture&);
85 Hcat_Pic(const Picture& l, const Picture& r):left(l),right(r){};
86 int height() const{ return max(left.height(),right.height());};
87 int width() const{ return left.width() + right.width();};
88 void display(ostream&, int ,int) const;
89 Picture left,right;
90 };
91
92 /*****类成员实现************************************************************************/
93 Picture::Picture(constchar*const* array, int n):p(new String_Pic(array,n))
94 {
95 }
96
97 Picture::Picture(const Picture& orig):p(orig.p)
98 {
99 orig.p->use++;
100 }
101
102 Picture::~Picture()
103 {
104 if(--p->use ==0)
105 delete p;
106 }
107
108 Picture& Picture::operator=(const Picture& orig)
109 {
110 orig.p->use++;
111 if(--p->use ==0)
112 delete p;
113 p = orig.p;
114 return*this;
115 }
116
117 int Picture::height() const
118 {
119 return p->height();
120 }
121
122 int Picture::width() const
123 {
124 return p->width();
125 }
126
127 void Picture::display(ostream& o, int x, int y) const
128 {
129 p->display(o, x, y);
130 }
131
132 String_Pic::String_Pic(constchar*const* p, int n) : data(newchar*[n]),size(n)
133 {
134 for(int i =0; i < n; i++)
135 {
136 data[i] =newchar[strlen(p[i]) +1];
137 strcpy(data[i], p[i]);
138 }
139 }
140
141 String_Pic::~String_Pic()
142 {
143 for(int i =0; i <size; i++)
144 delete[] data[i];
145 delete[] data; //注意此处销毁二维数组的方式
146 }
147
148 int String_Pic::height() const
149 {
150 return size;
151 };
152
153 int String_Pic::width() const
154 {
155 int n =0;
156 for(int i =0; i < size; i++)
157 {
158 n = max(n, strlen(data[i]));
159 }
160 return n;
161 };
162
163 void String_Pic::display(ostream& os, int row,int wid) const
164 {
165 int start =0;
166 if(row >=0&& row < height())
167 {
168 os << data[row];
169 start = strlen(data[row]);
170 }
171 pad(os, start, wid);
172 }
173
174 void Frame_Pic::display(ostream& os, int row, int wid) const
175 {
176 if(row <0|| row >= height())
177 {
178 //越界
179 pad(os, 0, wid);
180 }
181 else
182 {
183 if(row ==0|| row == height() -1)
184 {
185 os <<"+";
186 int i = p.width();
187 while(--i >=0)
188 os <<"-";
189 os <<"+";
190 }
191 else
192 {
193 os <<"|";
194 p.display(os, row -1, p.width());
195 os <<"|";
196 }
197 pad(os, width(), wid);
198 }
199 }
200
201 void Vcat_pic::display(ostream& os, int row, int wid) const
202 {
203 if(row >=0&& row < top.height())
204 top.display(os, row, wid);
205 elseif(row < top.height() + bottom.height())
206 bottom.display(os, row - top.height(), wid);
207 else
208 pad(os, 0, wid);
209 }
210
211 void Hcat_Pic::display(std::ostream & os, int row, int wid) const
212 {
213 left.display(os, row, left.width());
214 right.display(os, row, right.width());
215 pad(os, width(), wid);
216 }
217
218 /*****友元函数实现************************************************************************/
219 //加框函数
220 Picture frame(const Picture& p)
221 {
222 returnnew Frame_Pic(p);
223 }
224 //运算符重载,纵向合并
225 Picture operator&(const Picture& t, const Picture& b)
226 {
227 returnnew Vcat_pic(t, b);
228 }
229 //运算符重载,横向合并
230 Picture operator|(const Picture& l, const Picture& r)
231 {
232 returnnew Hcat_Pic(l, r);
233 }
234 //输出运算符重载
235 ostream&
236 operator<< (ostream& o, const Picture& p)
237 {
238 int ht = p.height();
239 for(int i =0; i < ht; i++)
240 {
241 p.display(o, i, 0); //原书勘误:p.display(o,i,o);
242 o << endl;
243 }
244 return o;
245 };
246 //负责打印y-x个空格
247 staticvoid pad(ostream& os, int x, int y)
248 {
249 for(int i = x; i < y; i++)
250 os <<"";
251 }
252
253 #endif

posted on 2010-02-08 16:35  blueclue  阅读(536)  评论(0编辑  收藏  举报