C++沉思录上提到的一道练习题及其源码实现

题目大意(具体问题可参考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   |      |        
|*------*      |        
+**************+        


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值