题目大意(具体问题可参考C++沉思录第九章):
现实中,一张图片,可以给予添加一层又一层片框,也可以和其他的图片组合在一块,或横,或竖,……,
如下图所示:
普通的图片:
wjj
lqm
lqmwjj
szb
加框的图片:
+******+
|wjj |
|lqm |
|lqmwjj|
|szb |
+******+
前两个图片横向连接,再纵向连接,再加框的图片
+**************+
|wjj +******+|
|lqm |wjj ||
|lqmwjj|lqm ||
|szb |lqmwjj||
| |szb ||
| +******+|
|+******+ |
||wjj | |
||lqm | |
||lqmwjj| |
||szb | |
|+******+ |
+**************+
默认情况下:横向连接顶端对齐,纵向连接左边对齐。
以下为自己看书后写的源代码:
picture.h
#ifndef _PICTURE_H
#define _PICTURE_H
#include <cstdlib>
#include <vector>
#include <string>
#include "pnode.h"
#include "string_pic.h"
//图片句柄类,又称作智能指针类
class Picture
{
//重载输出运算符
friend std::ostream & operator<<(std::ostream &os, const Picture &p);
friend class FramePic;
friend class VcatPic;
friend class HcatPic;
public:
Picture() : _p(NULL){}
Picture(const Picture & p) : _p(p._p)
{
++p._p->use;
}
Picture & operator=(const Picture &p)
{
if(_p != p._p)
{
if(--_p->use == 0)
{
delete _p;
}
_p = p._p;
++p._p->use;
}
return *this;
}
//默认构造StringPic类型的图片
Picture(const std::vector<std::string> &lines) : _p(new StringPic(lines))
{
}
~Picture()
{
if(--_p->use == 0)
delete _p;
}
//每次输出图片的一行,其实是调用的对应图像累的display函数
void display(std::ostream &os, int row) const;
//四个实用操作,原书采用的全局函数,这里用的类的静态成员函数
static const Picture Frame(const Picture &p, char corner_ch, char side_ch, char top_ch);
static void Reframe(const Picture &p, char corner_ch, char side_ch, char top_ch);
static const Picture Vcat(const Picture &top, const Picture &bottom);
static const Picture Hcat(const Picture &left, const Picture &right);
private:
int GetWidth() const
{
return _p->width;
}
int GetHeight() const
{
return _p->height;
}
//私有的构造函数,实现由实际图片类型的指针到Picture的隐式转换
Picture(Pnode *p) : _p(p)
{
++p->use;
}
//指向实际的图片类型
Pnode *_p;
};
#endif
picture.cpp
#include "picture.h"
#include "frame_pic.h"
#include "vcat_pic.h"
#include "hcat_pic.h"
void Picture::display(std::ostream &os, int row) const
{
_p->display(os,row);
}
std::ostream & operator<<(std::ostream &os, const Picture &p)
{
for(int i = 0; i < p.GetHeight() - 1; ++i)
{
p.display(os,i);
os << std::endl;
}
p.display(os,p.GetHeight() - 1);
return os;
}
const Picture Picture::Frame(const Picture &p, char corner_ch, char side_ch, char top_ch)
{
return new FramePic(p, corner_ch, side_ch, top_ch);
}
const Picture Picture::Vcat(const Picture &top, const Picture &bottom)
{
return new VcatPic(top, bottom);
}
const Picture Picture::Hcat(const Picture &left, const Picture &right)
{
return new HcatPic(left, right);
}
void Picture::Reframe(const Picture &p, char corner_ch, char side_ch, char top_ch)
{
static_cast<FramePic*>(p._p)->Reframe(corner_ch, side_ch, top_ch);
}
pnode.h
#ifndef _PNODE_H
#define _PNODE_H
#include <iosfwd>//输出流的前置声明
#include <string>
//图片类的基类,实现动态绑定
class Pnode
{
friend class Picture;
protected:
Pnode(int w, int h) : width(w), height(h), use(1){}
//重要的虚函数,每次显示一行图片内容
virtual void display(std::ostream &os, int row) const = 0;
//用于填充空格符
void pad(std::ostream &os, int num, char ch) const
{
for(int i = 0; i < num; ++i)
{
os << ch;
}
}
int width;
int height;
int use;//引用计数
};
#endif
string_pic.h
#ifndef _STRING_PIC_H
#define _STRING_PIC_H
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include "pnode.h"
class StringPic : public Pnode
{
friend class Picture;
struct StrShorter : std::binary_function<std::string, std::string, bool>
{
bool operator()(const std::string& str1, const std::string& str2) const
{
return str1.size() < str2.size();
}
};
StringPic(const std::vector<std::string> &lines);
virtual void display(std::ostream &os, int row) const;
std::vector<std::string> _lines;
};
#endif
string_pic.cpp
#include "string_pic.h"
StringPic::StringPic(const std::vector<std::string> &lines) :
Pnode(std::max_element(lines.begin(),lines.end(),StrShorter())->length(), lines.size()), _lines(lines)
{
++use;
}
void StringPic::display(std::ostream &os, int row) const
{
os << _lines[row];
pad(os,width - _lines[row].size(),' ');
}
frame_pic.h
#ifndef _FRAME_PIC_H
#define _FRAME_PIC_H
#include "picture.h"
#include "pnode.h"
class FramePic : public Pnode
{
friend class Picture;
FramePic(const Picture &p, char corner_ch, char side_ch, char top_ch);
virtual void display(std::ostream &os, int row) const;
void Reframe(char corner_ch, char side_ch, char top_ch);
Picture _p;
char _corner_ch;
char _side_ch;
char _top_ch;
};
#endif
frame_pic.cpp
#include "frame_pic.h"
FramePic::FramePic(const Picture &p, char corner_ch, char side_ch, char top_ch) :
Pnode(p.GetWidth()+2, p.GetHeight()+2),
_p(p), _corner_ch(corner_ch), _side_ch(side_ch), _top_ch(top_ch)
{
}
void FramePic::display(std::ostream &os, int row) const
{
if(row == 0 || row == height - 1)
{
os << _corner_ch;
for(int i = 0; i < width-2; ++i)
{
os << _top_ch;
}
os << _corner_ch;
}
if(row > 0 && row < height - 1)
{
os << _side_ch;
_p.display(os,row - 1);
os << _side_ch;
}
}
void FramePic::Reframe(char corner_ch, char side_ch, char top_ch)
{
_corner_ch = corner_ch;
_side_ch = side_ch;
_top_ch = top_ch;
}
vcat_pic.h
#ifndef _VCAT_PIC_H
#define _VCAT_PIC_H
#include "picture.h"
#include "pnode.h"
class VcatPic : public Pnode
{
friend class Picture;
VcatPic(const Picture &top_p, const Picture &bottom_p);
virtual void display(std::ostream &os, int row) const;
Picture _top_p;
Picture _bottom_p;
};
#endif
vcat_pic.cpp
#include "vcat_pic.h"
VcatPic::VcatPic(const Picture &top_p, const Picture &bottom_p) :
Pnode(std::max(top_p.GetWidth(), bottom_p.GetWidth()), top_p.GetHeight() + bottom_p.GetHeight()),
_top_p(top_p), _bottom_p(bottom_p)
{
}
void VcatPic::display(std::ostream &os, int row) const
{
if(row < _top_p.GetHeight())
{
_top_p.display(os,row);
pad(os,width - _top_p.GetWidth(),' ');
}
else
{
_bottom_p.display(os,row - _top_p.GetHeight());
pad(os,width - _bottom_p.GetWidth(),' ');
}
}
hcat_pic.h
#ifndef _HCAT_PIC_H
#define _HCAT_PIC_H
#include "picture.h"
#include "pnode.h"
class HcatPic : public Pnode
{
friend class Picture;
HcatPic(const Picture &lpic,const Picture &rpic);
virtual void display(std::ostream &os, int row) const;
Picture _lpic;
Picture _rpic;
};
#endif
hcat_pic.cpp
#include "hcat_pic.h"
HcatPic::HcatPic(const Picture &lpic,const Picture &rpic) :
Pnode(lpic.GetWidth() + rpic.GetWidth(), std::max(lpic.GetHeight(), rpic.GetHeight())),
_lpic(lpic), _rpic(rpic)
{
}
void HcatPic::display(std::ostream &os, int row) const
{
if(row < _lpic.GetHeight())
_lpic.display(os,row);
else
pad(os,_lpic.GetWidth(),' ');
if(row < _rpic.GetHeight())
_rpic.display(os,row);
else
pad(os,_rpic.GetWidth(),' ');
}
main.cpp
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include "picture.h"
using namespace std;
int main(int argc, char *argv[])
{
ofstream outfile("d:/hello.txt");
//图像信息保存在vector中,原书用的字符数组
//目前写c++程序建议用vector代替数组
vector<string> pic;
pic.push_back("wjj");
pic.push_back("lqm");
pic.push_back("lqmwjj");
pic.push_back("szb");
//创建一个图片
Picture p(pic);
outfile << p << endl;
//创建一个加边框的图片
Picture frame_pic = Picture::Frame(pic,'+','|','*');
outfile << frame_pic << endl;
//综合使用横向连接与纵向连接
Picture all_p = Picture::Frame(Picture::Vcat(Picture::Hcat(pic,frame_pic), frame_pic),'+','|','*');
outfile << all_p << endl;
//改变图像的边框样式
Picture::Reframe(frame_pic, '*', '|', '-');
outfile << frame_pic << endl;
//再连接一次
outfile << Picture::Hcat(all_p,frame_pic) << endl;
return 0;
}
测试输出结果:hello.txt
wjj
lqm
lqmwjj
szb
+******+
|wjj |
|lqm |
|lqmwjj|
|szb |
+******+
+**************+
|wjj +******+|
|lqm |wjj ||
|lqmwjj|lqm ||
|szb |lqmwjj||
| |szb ||
| +******+|
|+******+ |
||wjj | |
||lqm | |
||lqmwjj| |
||szb | |
|+******+ |
+**************+
*------*
|wjj |
|lqm |
|lqmwjj|
|szb |
*------*
+**************+*------*
|wjj *------*||wjj |
|lqm |wjj |||lqm |
|lqmwjj|lqm |||lqmwjj|
|szb |lqmwjj|||szb |
| |szb ||*------*
| *------*|
|*------* |
||wjj | |
||lqm | |
||lqmwjj| |
||szb | |
|*------* |
+**************+