《C++沉思录》-第十章- 一个课堂练习的分析(下)
2013-12-11 21:17
369 查看
第九章中最大的弊端,在于图像对象一旦生成,其结构信息立刻就会丢掉。那我们该怎么做?
第一个结论:可以存储几种不同的图像。
第二个结论:不必复制图像内容。
为了能使用继承来区分和组织各种图像,显然要用指针。并且我们需要想办法隐藏其中实现细节。正如第八章,我们需要一个Handle类,且称之为Picture,我们用它来隐藏根据所建立的图像结构而设计的派生层次。一旦我们有了Handle类,就可以实现引用计数的内存管理策略,从而避免复制那些构成图像的底层字符。
picture.h
picture.cpp
main.cp
运行结果:
结论:
1、在解决问题时,不仅要看眼前的问题,还要看到长远的变化。
在这个特定的问题里,最重要的一个认识是,图像是有结构的,总有一天我们会考虑到这些结构。而这种认识使我们不仅仅存储所产生的图像内容,而是要主动想办法存储这些结构。
2、我们可以使用继承对这些结构进行建模。
当我们说类似“所有图像都可以加边框,得到一幅新的图像”这样的话时,通常就是继承可以最准确有效地发挥威力的时候。一旦我们决定使用继承,就会明白,其实无需拷贝图像的内容,这一认识使得我们利用引用计数技术来管理内存。
3、最后,我们可以认识到即使需要显示图像,也无需重新设置图像的字符。相反,我们可以一次显示一行,将所需要的那一行的字符内容“立即”构建出来并输出显示”。
第一个结论:可以存储几种不同的图像。
第二个结论:不必复制图像内容。
为了能使用继承来区分和组织各种图像,显然要用指针。并且我们需要想办法隐藏其中实现细节。正如第八章,我们需要一个Handle类,且称之为Picture,我们用它来隐藏根据所建立的图像结构而设计的派生层次。一旦我们有了Handle类,就可以实现引用计数的内存管理策略,从而避免复制那些构成图像的底层字符。
picture.h
#ifndef PICTURE_H #define PICTURE_H #include <iostream> class P_Node; class Picture { friend Picture reframe(const Picture&, char, char, char); friend std::ostream& operator<<(std::ostream&, const Picture&); friend Picture frame(const Picture&); friend Picture operator&(const Picture&, const Picture&); friend Picture operator|(const Picture&, const Picture&); friend class String_Pic; friend class Frame_Pic; friend class HCat_Pic; friend class VCat_Pic; public: Picture(const char* const*, int); Picture(const Picture&); Picture& operator=(const Picture&); ~Picture(); private: P_Node* m_p; //这个构造函数作为隐式转型操作符,应用于链接操作 Picture(P_Node*); int height() const; int width() const; void display(std::ostream&, int, int) const; }; class P_Node { friend class Picture; friend Picture reframe(const Picture&, char, char, char); protected: P_Node(); virtual ~P_Node(); virtual int height() const = 0; virtual int width() const = 0; virtual void display(std::ostream&, int, int) const = 0; int max(int x, int y) const; virtual Picture reframe(char, char, char) = 0; int m_use; }; class String_Pic: public P_Node { friend class Picture; String_Pic(const char* const*, int); ~String_Pic(); int height() const; int width() const; void display(std::ostream&, int, int) const; Picture reframe(char c, char s, char t); char** m_data; int m_size; }; class Frame_Pic: public P_Node { friend Picture frame(const Picture&); Frame_Pic(const Picture&, char c='+', char s='|', char t='-'); int height() const; int width() const; void display(std::ostream&, int, int) const; Picture reframe(char c, char s, char t); Picture m_p; char m_corner; char m_sideBorder; char m_topBorder; }; class VCat_Pic: public P_Node { friend Picture operator&(const Picture&, const Picture&); VCat_Pic(const Picture&, const Picture&); int height() const; int width() const; void display(std::ostream&, int, int) const; Picture reframe(char c, char s, char t); Picture m_top; Picture m_bottom; }; class HCat_Pic: public P_Node { friend Picture operator|(const Picture&, const Picture&); HCat_Pic(const Picture&, const Picture&); int height() const; int width() const; void display(std::ostream&, int, int) const; Picture reframe(char c, char s, char t); Picture m_left; Picture m_right; }; #endif // PICTURE_H
picture.cpp
#include "picture.h" #include "string.h" Picture reframe(const Picture& pic, char c, char s, char t) { return pic.m_p->reframe(c, s, t); } std::ostream& operator<<(std::ostream& os, const Picture& picture) { int ht = picture.height(); for (int i=0; i<ht; ++i) { picture.display(os, i, picture.width()); os << std::endl; } return os; } int P_Node::max(int x, int y) const { return x > y ? x : y; } P_Node::P_Node() :m_use(1) { } P_Node::~P_Node() { } /************end Picture****************/ String_Pic::String_Pic(const char* const* array, int n) :m_data(new char* ), m_size(n) { for (int i=0; i<n; ++i) { m_data[i] = new char[strlen(array[i]) + 1]; strcpy(m_data[i], array[i]); } } String_Pic::~String_Pic() { for (int i=0; i<m_size; ++i) delete[] m_data[i]; delete[] m_data; } int String_Pic::height() const { return m_size; } int String_Pic::width() const { int n = 0; for (int i=0; i<m_size; ++i) { n = max(n, strlen(m_data[i])); } return n; } static void pad(std::ostream& os, int x, int y) { for (int i=x; i<y; ++i) { os << " "; } } void String_Pic::display(std::ostream& os, int row, int width) const { int start = 0; if (row >= 0 && row < height()) { os << m_data[row]; start = strlen(m_data[row]); } pad(os, start, width); } Picture String_Pic::reframe(char, char, char) { //增加引用计数,以表明还有另一个用户在使用底层的String_Pic, //使用P_Node*的转型操作从this生成一个新的Picture. ++m_use; return this;//使用私有Picture构造函数 } /************end String_Pic****************/ Picture frame(const Picture& pic) { return new Frame_Pic(pic); } Frame_Pic::Frame_Pic(const Picture& pic, char c, char s, char t) :m_p(pic), m_corner(c), m_sideBorder(s), m_topBorder(t) { } int Frame_Pic::height() const { return m_p.height() + 2; } int Frame_Pic::width() const { return m_p.width() + 2; } void Frame_Pic::display(std::ostream& os, int row, int width) const { if (row<0 || row>=height()) pad(os, 0, width); else { if (row==0 || row==height()-1) { //顶框和底框 os << m_corner;//"+"; int i = m_p.width(); while (--i >= 0) os<< m_topBorder;//"-"; os << m_corner;//"+"; } else { //内部行 os << m_sideBorder;//"|"; m_p.display(os, row-1, m_p.width()); os << m_sideBorder;//"|"; } pad(os, this->width(), width); } } Picture Frame_Pic:: reframe(char c, char s, char t) { return new Frame_Pic(::reframe(m_p, c, s, t), c, s, t); } /************end Frame_Pic****************/ VCat_Pic::VCat_Pic(const Picture& top, const Picture& bottom) :m_top(top), m_bottom(bottom) { } Picture operator&(const Picture& top, const Picture& bottom) { return new VCat_Pic(top, bottom); } int VCat_Pic::height() const { return m_top.height() + m_bottom.height(); } int VCat_Pic::width() const { return max(m_top.width(), m_bottom.width()); } void VCat_Pic::display(std::ostream& os, int row , int width) const { if (row>=0 && row< m_top.height()) { m_top.display(os, row, width); } else if (row < m_top.height() + m_bottom.height()) { m_bottom.display(os, row-m_top.height(), width); } else { pad(os, 0, width); } } Picture VCat_Pic::reframe(char c, char s, char t) { return new VCat_Pic(::reframe(m_top, c, s, t), ::reframe(m_bottom, c, s, t)); } /************end VCat_Pic****************/ HCat_Pic::HCat_Pic(const Picture& left, const Picture& right) :m_left(left), m_right(right) { } Picture operator|(const Picture& left, const Picture& right) { return new HCat_Pic(left, right); } int HCat_Pic::height() const { return max(m_left.height(), m_right.height()); } int HCat_Pic::width() const { return m_left.width() + m_right.width(); } void HCat_Pic::display(std::ostream& os, int row, int width) const { m_left.display(os, row, m_left.width()); m_right.display(os, row, m_right.width()); pad(os, this->width(), width); } Picture HCat_Pic::reframe(char c, char s, char t) { return new HCat_Pic(::reframe(m_left, c, s, t), ::reframe(m_right, c, s, t)); } /************end HCat_Pic****************/ Picture::Picture(P_Node* p) :m_p(p) { } Picture::Picture(const char* const* array, int n) :m_p(new String_Pic(array, n)) { } Picture::Picture(const Picture& orig) :m_p(orig.m_p) { orig.m_p->m_use++; } Picture& Picture::operator=(const Picture& orig) { ++orig.m_p->m_use; if (--m_p->m_use == 0) delete m_p; m_p = orig.m_p; return *this; } Picture::~Picture() { if (--m_p->m_use == 0) delete m_p; } int Picture::height() const { return m_p->height(); } int Picture::width() const { return m_p->width(); } void Picture::display(std::ostream& o, const int x, const int y) const { m_p->display(o, x, y); } /************end Picture****************/
main.cp
#include <iostream> #include "picture.h" using namespace std; char* init[] = {"Pairs", "in the", "Spring"}; int main() { Picture p(init, 3); cout << p << endl; Picture q = p; cout << q << endl; Picture fq = frame(q); cout << fq << endl; Picture fqq = (fq & q); cout << fqq << endl; Picture p_fqq = p | fqq; cout << p_fqq << endl; Picture fpfqq = frame(p_fqq); cout << fpfqq << endl; Picture re = reframe(fpfqq, '*', '!', '~'); cout << re << endl; return 0; }
运行结果:
jet@ubuntu:~/c++_workplace/Ruminations_on_C++/pictureDemo2$ ./pictureDemo2 Pairs in the Spring Pairs in the Spring +------+ |Pairs | |in the| |Spring| +------+ +------+ |Pairs | |in the| |Spring| +------+ Pairs in the Spring Pairs +------+ in the|Pairs | Spring|in the| |Spring| +------+ Pairs in the Spring +--------------+ |Pairs +------+| |in the|Pairs || |Spring|in the|| | |Spring|| | +------+| | Pairs | | in the | | Spring | +--------------+ *~~~~~~~~~~~~~~* !Pairs *~~~~~~*! !in the!Pairs !! !Spring!in the!! ! !Spring!! ! *~~~~~~*! ! Pairs ! ! in the ! ! Spring ! *~~~~~~~~~~~~~~*
结论:
1、在解决问题时,不仅要看眼前的问题,还要看到长远的变化。
在这个特定的问题里,最重要的一个认识是,图像是有结构的,总有一天我们会考虑到这些结构。而这种认识使我们不仅仅存储所产生的图像内容,而是要主动想办法存储这些结构。
2、我们可以使用继承对这些结构进行建模。
当我们说类似“所有图像都可以加边框,得到一幅新的图像”这样的话时,通常就是继承可以最准确有效地发挥威力的时候。一旦我们决定使用继承,就会明白,其实无需拷贝图像的内容,这一认识使得我们利用引用计数技术来管理内存。
3、最后,我们可以认识到即使需要显示图像,也无需重新设置图像的字符。相反,我们可以一次显示一行,将所需要的那一行的字符内容“立即”构建出来并输出显示”。
相关文章推荐
- 《C++沉思录》-第九章-- 一个课堂练习的分析(上)
- 一个课堂打印案例分析——《C++沉思录》第9章
- 课堂练习----一个整数数组中最大子数组的和(2)
- Lesson 3 上机练习题——继承 课堂练习: – 在包bzu.aa中定义一个交通工具类(Vehicle): 属性——载客量(capacity) 方法 无参构造方法(给capacity初
- 3月20号周五课堂练习:结对练习----电梯调度需求分析
- 课堂练习3: 定义一个平面中的Circle类
- 课堂练习(返回一个环状一维整数数组中最大子数组的和)
- 课堂练习:返回一个整数数组中最大子数组的和
- 课堂练习----一个整数数组中最大子数组的和(1)
- 2016年秋季-课堂练习1-Liz开发问题账户分析系统
- 课堂练习1: 请定义一个交通工具(Vehicle)的类
- 4月17号周五课堂练习:用户场景分析
- DW课堂练习 用所学的知识去制作一个 (邮箱的注册页面)
- 3月17号周二课堂练习:结对开发----返回一个整数数组中最大子数组的和一
- 课堂练习3: 定义一个平面中的Circle类
- 3月27号周五课堂练习:结对开发----返回一个整数数组中最大子数组的和三
- 课堂练习----一个整数数组中最大子数组的和(1)
- 课堂练习4: 编写代码模拟手机与SIM卡的组合关系。 要求: SIM卡类负责创建SIM卡; Phone类负责创建手机; 手机可以组合一个
- 课堂练习四: 返回一个整数数组中最大子数组的和。
- 课堂练习4: 编写代码模拟手机与SIM卡的组合关系。 要求: SIM卡类负责创建SIM卡; Phone类负责创建手机; 手机可以组合一个