您的位置:首页 > 编程语言 > C语言/C++

《C++沉思录》-第十章- 一个课堂练习的分析(下)

2013-12-11 21:17 369 查看
第九章中最大的弊端,在于图像对象一旦生成,其结构信息立刻就会丢掉。那我们该怎么做?

第一个结论:可以存储几种不同的图像。
第二个结论:不必复制图像内容。

为了能使用继承来区分和组织各种图像,显然要用指针。并且我们需要想办法隐藏其中实现细节。正如第八章,我们需要一个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、最后,我们可以认识到即使需要显示图像,也无需重新设置图像的字符。相反,我们可以一次显示一行,将所需要的那一行的字符内容“立即”构建出来并输出显示”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐