0
点赞
收藏
分享

微信扫一扫

第十五章习题 再探字符图形

AbrahamW 2022-05-26 阅读 9


文章目录

  • ​​1 编译运行本章示例​​
  • ​​2 执行下面的语句​​
  • ​​3 重写Frame_Pic类,在源图形上加上边框使用三种字符:一种用于边框的4个角;另一种字符用于定边和底边;还有一种用于两条垂直的边。​​
  • ​​3 改写上面的类让用户能够自己选择用何种字符形成边框​​
  • ​​4 加入一个操作函数,用于为一个图形重加边框,它可以改变边线的字符。这个函数要求改变内部图形的全部边框。​​
  • ​​5 重写HCat_Pic类,要求不同大小的子图形在连接时,较小的图形必须在大图形的中间位置与较大图形连接。也就是说,如果水平地连接两个子图形,并且其中一个子图形有4行,而且另一个子图形有两行,那么在输出这个子图形时,要在它的顶上与底下多输出一个空格。注意,这时候某行内存在子图形中的相对号与以前版本有所不同。​​
  • ​​6 使用前写的Str类和Vec类实现Picture类,并编程测试。​​

1 编译运行本章示例

头文件:

//
// Created by MacBook Pro on 2020-03-20.
//

#ifndef ACM_PICTURE_H
#define ACM_PICTURE_H

#include
#include
#include
#include
#include "Ptr.h"

class Picture;

//基类
class Pic_base {
friend class String_Pic;
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend std::ostream& operator<<(std::ostream& , const Picture& );

typedef std::vector<std::string>::size_type ht_sz;//高
typedef std::vector<std::string>::size_type wd_sz;//宽

//纯虚拟函数
virtual wd_sz width() const = 0;//纯虚拟函数
virtual ht_sz height() const = 0;
virtual void display(std::ostream &, ht_sz, bool) const = 0;//输出内容
protected:
//静态成员,不属于类的某个对象
//减少定义全局函数或变量
static void pad(std::ostream& os, wd_sz beg, wd_sz end){
while(beg != end){
os <<" ";
++beg;
}
}
public:
//虚拟函数
virtual ~Pic_base(){}
};

//派生类
class String_Pic:public Pic_base{
friend class Picture;

std::vector<std::string> data;

String_Pic(const std::vector<std::string>& v):data(v){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::ht_sz String_Pic::height() const {
return data.size();
}

Pic_base::wd_sz String_Pic::width() const {
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i) {
n = std::max(n, data[i].size());
}
return n;
}

void String_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
Pic_base::wd_sz start = 0;
//如果row没有超出范围,就输出第row行
if(row < height()){
os << data[row];
start = data[row].size();
}
//如果有必要,补齐输出各行
if(do_pad){
pad(os, start, width());
}
}

class Frame_Pic:public Pic_base{
friend Picture frame(const Picture& );
Ptr<Pic_base> p;
//构造函数
Frame_Pic(const Ptr<Pic_base>& pic):p(pic){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz Frame_Pic::width() const {
return p->width() + 4;
}

Pic_base::ht_sz Frame_Pic::height() const {
return p->height() + 4;
}


void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << std::string(width(), '*');
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << "*";
pad(os, 1, width() - 1);
os << "*";
}else{
//在内部图形
os << "* ";
p->display(os, row - 2, true);
os << " *";
}
}
}

class VCat_Pic:public Pic_base{
friend Picture vcat(const Picture&, const Picture&);

Ptr<Pic_base> top, bottom;
//构造
VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):top(t),bottom(b){}
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz VCat_Pic::width() const {
return std::max(top->width(), bottom->width());
}

Pic_base::ht_sz VCat_Pic::height() const {
return top->height() + bottom->height();
}

void VCat_Pic::display(std::ostream & os, Pic_base::ht_sz row, bool do_pad) const {
wd_sz w = 0;
if(row < top->height()){
//处于上面的子图形中
top->display(os, row, do_pad);
w = top->width();
}else if(row < height()){
//处于下面的子图形中
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if(do_pad){
pad(os, w, width());
}
}



class HCat_Pic:public Pic_base{
friend Picture hcat(const Picture&, const Picture&);

Ptr<Pic_base>left, right;

HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):left(l),right(r){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz HCat_Pic::width() const {
return left->width() + right->width();
}

Pic_base::ht_sz HCat_Pic::height() const {
return std::max(left->height(), right->height());
}

void HCat_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
left->display(os, row, do_pad|| row < right->height());
right->display(os, row, do_pad);
}

//接口类
class Picture{
friend Picture frame(const Picture&);
friend Picture hcat(const Picture& , const Picture& );
friend Picture vcat(const Picture&, const Picture&);
friend std::ostream& operator<<(std::ostream& , const Picture& );
public:

//从一个装有string类型对象的容器中获得数据
Picture(const std::vector<std::string>& = std::vector<std::string>());

private:
Ptr<Pic_base>p;
//构造函数提供类型转换
Picture(Pic_base* ptr):p(ptr){}


};

Picture frame(const Picture& pic){
return new Frame_Pic(pic.p);
// Pic_base* temp1 = new Frame_Pic(pic.p);//生成一个新Frame_Pic对象
// Picture temp2(temp1);//使用一个Pic_base*指针构造一个Pictrue类型对象
// return temp2;//返回一个Picture类型对象,这将激活Picture类的复制构造函数
}

Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}

//为vector类型构造Picture类型对象
Picture::Picture(const std::vector<std::string>& v):p(new String_Pic(v)){}

std::ostream& operator<<(std::ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << std::endl;
}
return os;
}

#endif //ACM_PICTURE_H

#ifndef ACM_PTR_H
#define ACM_PTR_H

#include "Refptr.h"
#include "Student_info.h"

template <class T>T* clone(const T* tp){
return tp->clone();
}

template <class T>
class Ptr{
public:
//在需要时有条件复制对象

void make_unique(){
if(*refptr != 1){
--*refptr;
refptr = new size_t(1);
p = p?clone(p):0;
}
}
Ptr():p(0),refptr(new size_t(1)){}
Ptr(T* t):p(t),refptr(new size_t(1)){}
Ptr(const Ptr& h):p(h.p),refptr(h.refptr){++*refptr;}

Ptr& operator=(const Ptr&);
~Ptr();
operator bool() const {return p;}
T& operator*() const{
if(p) return *p;
throw std::runtime_error("unbound Ptr");
}
T* operator->() const{
if(p) return p;
throw std::runtime_error("unbound Ptr");
}
private:
T* p;
std::size_t * refptr;
};

template <class T>
Ptr<T>& Ptr<T>::operator=(const Ptr &rhs) {
++*rhs.refptr;
if(--*refptr == 0){
delete(refptr);
delete(p);
}

refptr = rhs.refptr;
p = rhs.p;
return *this;
}

template <class T>
Ptr<T>::~Ptr() {
if(--*refptr==0){
delete(refptr);
delete(p);
}
}
#endif //ACM_PTR_H

2 执行下面的语句

源程序:

#include 
#include
#include
#include "Picture.h"

using std::endl; using std::cin;
using std::cout;
using std::string; using std::vector;

//分割字符串
vector<string> split(const string& s){
vector<string> ret;
typedef string::size_type string_size;
string_size i = 0;

while(i != s.size()){
//忽略前段的空白:[先前的i,i)中全部字符都是空格
while(i != s.size() && isspace(s[i])){
i++;
}
//找出下一个单词的终结点
string_size j = i;
//[先前的j,j)中的任意字符都不是空格
while(j != s.size() && !isspace(s[j])){
j++;
}
//找到了一些非空白符
if(i != j){
ret.push_back(s.substr(i, j - i));
i = j;
}
}
return ret;
}



int main(int argc, char** argv){
string str;
getline(cin, str);
vector<string> vs = split(str);

Picture p = vs;
Picture q = frame(p);
Picture r = hcat(p, q);//横向
Picture s = vcat(q, r);//纵向
cout << frame(hcat(s, vcat(r, q))) << endl;


return 0;
}

结果:
第十五章习题 再探字符图形_ide

3 重写Frame_Pic类,在源图形上加上边框使用三种字符:一种用于边框的4个角;另一种字符用于定边和底边;还有一种用于两条垂直的边。

改写:Frame_Pic类的成员函数:

void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << "#"<<std::string(width()-2, '*')<<"#";
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << "$";
pad(os, 1, width() - 1);
os << "$";
}else{
//在内部图形
os << "$ ";
p->display(os, row - 2, true);
os << " $";
}
}
}

结果:
第十五章习题 再探字符图形_#include_02

3 改写上面的类让用户能够自己选择用何种字符形成边框

在Frame_Pic增加一个构造函数、相应的数据成员以及修改display函数,在Picture增加构造函数的友元,同时修改非成员函数frame。

class Picture{
friend Picture frame(const Picture&, const char, const char, const char);//增加
//...
}
Picture frame(const Picture& pic, const char cor, const char tb, const char sd){
return new Frame_Pic(pic.p, cor, tb, sd);

}

class Frame_Pic:public Pic_base{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);//增加

Ptr<Pic_base> p;//增加
char corner;//增加
char top_bottom;//增加
char side;
//构造函数
// Frame_Pic(const Ptr& pic):p(pic){}
//增加
Frame_Pic(const Ptr<Pic_base>& pic, const char corner = '$',
const char top_bottom = '-', const char side = '|')
:p(pic),corner(corner), top_bottom(top_bottom),side(side){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

//重写
void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << corner <<std::string(width()-2, top_bottom)<< corner;
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << side;
pad(os, 1, width() - 1);
os << side;
}else{
//在内部图形
os << side <<" ";
p->display(os, row - 2, true);
os <<" "<<side;
}
}
}

完整程序:
头文件:(句柄类同前)

//
// Created by MacBook Pro on 2020-03-20.
//

#ifndef ACM_PICTURE_H
#define ACM_PICTURE_H

#include
#include
#include
#include
#include "Ptr.h"

class Picture;

//基类
class Pic_base {
friend class String_Pic;
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend std::ostream& operator<<(std::ostream& , const Picture& );

typedef std::vector<std::string>::size_type ht_sz;//高
typedef std::vector<std::string>::size_type wd_sz;//宽

//纯虚拟函数
virtual wd_sz width() const = 0;//纯虚拟函数
virtual ht_sz height() const = 0;
virtual void display(std::ostream &, ht_sz, bool) const = 0;//输出内容
protected:
//静态成员,不属于类的某个对象
//减少定义全局函数或变量
static void pad(std::ostream& os, wd_sz beg, wd_sz end){
while(beg != end){
os <<" ";
++beg;
}
}
public:
//虚拟函数
virtual ~Pic_base(){}
};

//派生类
class String_Pic:public Pic_base{
friend class Picture;

std::vector<std::string> data;

String_Pic(const std::vector<std::string>& v):data(v){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::ht_sz String_Pic::height() const {
return data.size();
}

Pic_base::wd_sz String_Pic::width() const {
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i) {
n = std::max(n, data[i].size());
}
return n;
}

void String_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
Pic_base::wd_sz start = 0;
//如果row没有超出范围,就输出第row行
if(row < height()){
os << data[row];
start = data[row].size();
}
//如果有必要,补齐输出各行
if(do_pad){
pad(os, start, width());
}
}

class Frame_Pic:public Pic_base{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);

Ptr<Pic_base> p;
char corner;
char top_bottom;
char side;
//构造函数
// Frame_Pic(const Ptr& pic):p(pic){}
Frame_Pic(const Ptr<Pic_base>& pic, const char corner = '$',
const char top_bottom = '-', const char side = '|')
:p(pic),corner(corner), top_bottom(top_bottom),side(side){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz Frame_Pic::width() const {
return p->width() + 4;
}

Pic_base::ht_sz Frame_Pic::height() const {
return p->height() + 4;
}


void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << corner <<std::string(width()-2, top_bottom)<< corner;
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << side;
pad(os, 1, width() - 1);
os << side;
}else{
//在内部图形
os << side <<" ";
p->display(os, row - 2, true);
os <<" "<<side;
}
}
}

class VCat_Pic:public Pic_base{
friend Picture vcat(const Picture&, const Picture&);

Ptr<Pic_base> top, bottom;
//构造
VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):top(t),bottom(b){}
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz VCat_Pic::width() const {
return std::max(top->width(), bottom->width());
}

Pic_base::ht_sz VCat_Pic::height() const {
return top->height() + bottom->height();
}

void VCat_Pic::display(std::ostream & os, Pic_base::ht_sz row, bool do_pad) const {
wd_sz w = 0;
if(row < top->height()){
//处于上面的子图形中
top->display(os, row, do_pad);
w = top->width();
}else if(row < height()){
//处于下面的子图形中
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if(do_pad){
pad(os, w, width());
}
}

class HCat_Pic:public Pic_base{
friend Picture hcat(const Picture&, const Picture&);

Ptr<Pic_base>left, right;

HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):left(l),right(r){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
};

Pic_base::wd_sz HCat_Pic::width() const {
return left->width() + right->width();
}

Pic_base::ht_sz HCat_Pic::height() const {
return std::max(left->height(), right->height());
}

void HCat_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
left->display(os, row, do_pad|| row < right->height());
right->display(os, row, do_pad);
}

//接口类
class Picture{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);
friend Picture hcat(const Picture& , const Picture& );
friend Picture vcat(const Picture&, const Picture&);
friend std::ostream& operator<<(std::ostream& , const Picture& );
public:

//从一个装有string类型对象的容器中获得数据
Picture(const std::vector<std::string>& = std::vector<std::string>());

private:
Ptr<Pic_base>p;
//构造函数提供类型转换
Picture(Pic_base* ptr):p(ptr){}


};

Picture frame(const Picture& pic, const char cor, const char tb, const char sd){
return new Frame_Pic(pic.p, cor, tb, sd);

}

Picture frame(const Picture& pic) {
return new Frame_Pic(pic.p);
// Pic_base* temp1 = new Frame_Pic(pic.p);//生成一个新Frame_Pic对象
// Picture temp2(temp1);//使用一个Pic_base*指针构造一个Pictrue类型对象
// return temp2;//返回一个Picture类型对象,这将激活Picture类的复制构造函数
}

Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}

//为vector类型构造Picture类型对象
Picture::Picture(const std::vector<std::string>& v):p(new String_Pic(v)){}

std::ostream& operator<<(std::ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << std::endl;
}
return os;
}

#endif //ACM_PICTURE_H

测试程序:

int main(int argc, char** argv){
vector<string> v1 = { "one test", "two test", "ohohoh GeeGeeGee" };
Picture p = v1;
Picture q = frame(p, '+', '*', '*');
Picture r = hcat(p, q);
Picture s = vcat(q, r);
cout << frame(hcat(s, vcat(r, q))) << endl;
return 0;
}

4 加入一个操作函数,用于为一个图形重加边框,它可以改变边线的字符。这个函数要求改变内部图形的全部边框。

在基类Pic_base中加入纯虚拟函数reframe,然后在每个派生类中实现它。为了能让Picture类中的reframe函数能访问基类的ragrame函数,把Picture声明为Pic_base的友元函数。

基类Pic_base中加入:

virtual void reframe(const char, const char, const char)  = 0;

派生类Frame_Pic中声明并实现:

class Frame_Pic:public Pic_base{
void reframe(const char, const char, const char);
//。。。。
}
void Frame_Pic::reframe(const char cor, const char tb, const char sd) {
this->corner = cor;
this->top_bottom = tb;
this->side = sd;

p->reframe(cor, tb, sd);
}

其他类的实现:

void VCat_Pic::reframe(const char cor, const char tb, const char sd) {
top->reframe(cor, tb, sd);
bottom->reframe(cor, tb, sd);
}

void HCat_Pic::reframe(const char cor, const char tb, const char sd) {
left->reframe(cor, tb, sd);
right->reframe(cor, tb, sd);
}
class String_Pic:public Pic_base{
void reframe(const char, const char, const char){};
//....
};
class Picture{
public:
//由于改变了对象的状态
void reframe(const char, const char, const char);
//...
}
void Picture::reframe(const char corner, const char top_bottom, const char side) {
p->reframe(corner, top_bottom, side);
}

完整头文件:

//
// Created by MacBook Pro on 2020-03-20.
//

#ifndef ACM_PICTURE_H
#define ACM_PICTURE_H

#include
#include
#include
#include
#include "Ptr.h"

class Picture;

class Pic_base;
//基类
class Pic_base {
friend class String_Pic;
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend class Picture;

friend std::ostream& operator<<(std::ostream& , const Picture& );

typedef std::vector<std::string>::size_type ht_sz;//高
typedef std::vector<std::string>::size_type wd_sz;//宽

//纯虚拟函数
virtual wd_sz width() const = 0;//纯虚拟函数
virtual ht_sz height() const = 0;
virtual void display(std::ostream &, ht_sz, bool) const = 0;//输出内容
virtual void reframe(const char, const char, const char) = 0;
protected:
//静态成员,不属于类的某个对象
//减少定义全局函数或变量
static void pad(std::ostream& os, wd_sz beg, wd_sz end){
while(beg != end){
os <<" ";
++beg;
}
}
public:
//虚拟函数
virtual ~Pic_base(){}
};

//派生类
class String_Pic:public Pic_base{
friend class Picture;

std::vector<std::string> data;

String_Pic(const std::vector<std::string>& v):data(v){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char){};
};


Pic_base::ht_sz String_Pic::height() const {
return data.size();
}

Pic_base::wd_sz String_Pic::width() const {
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i) {
n = std::max(n, data[i].size());
}
return n;
}

void String_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
Pic_base::wd_sz start = 0;
//如果row没有超出范围,就输出第row行
if(row < height()){
os << data[row];
start = data[row].size();
}
//如果有必要,补齐输出各行
if(do_pad){
pad(os, start, width());
}
}

class Frame_Pic:public Pic_base{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);

Ptr<Pic_base> p;
char corner;
char top_bottom;
char side;
//构造函数
// Frame_Pic(const Ptr& pic):p(pic){}
Frame_Pic(const Ptr<Pic_base>& pic, const char corner = '$',
const char top_bottom = '-', const char side = '|')
:p(pic),corner(corner), top_bottom(top_bottom),side(side){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz Frame_Pic::width() const {
return p->width() + 4;
}

Pic_base::ht_sz Frame_Pic::height() const {
return p->height() + 4;
}


void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << corner <<std::string(width()-2, top_bottom)<< corner;
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << side;
pad(os, 1, width() - 1);
os << side;
}else{
//在内部图形
os << side <<" ";
p->display(os, row - 2, true);
os <<" "<<side;
}
}
}


void Frame_Pic::reframe(const char cor, const char tb, const char sd) {
this->corner = cor;
this->top_bottom = tb;
this->side = sd;

p->reframe(cor, tb, sd);
}
class VCat_Pic:public Pic_base{
friend Picture vcat(const Picture&, const Picture&);

Ptr<Pic_base> top, bottom;
//构造
VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):top(t),bottom(b){}
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz VCat_Pic::width() const {
return std::max(top->width(), bottom->width());
}

Pic_base::ht_sz VCat_Pic::height() const {
return top->height() + bottom->height();
}

void VCat_Pic::display(std::ostream & os, Pic_base::ht_sz row, bool do_pad) const {
wd_sz w = 0;
if(row < top->height()){
//处于上面的子图形中
top->display(os, row, do_pad);
w = top->width();
}else if(row < height()){
//处于下面的子图形中
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if(do_pad){
pad(os, w, width());
}
}

void VCat_Pic::reframe(const char cor, const char tb, const char sd) {
top->reframe(cor, tb, sd);
bottom->reframe(cor, tb, sd);
}

class HCat_Pic:public Pic_base{
friend Picture hcat(const Picture&, const Picture&);

Ptr<Pic_base>left, right;

HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):left(l),right(r){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz HCat_Pic::width() const {
return left->width() + right->width();
}

Pic_base::ht_sz HCat_Pic::height() const {
return std::max(left->height(), right->height());
}

void HCat_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
left->display(os, row, do_pad|| row < right->height());
right->display(os, row, do_pad);
}

void HCat_Pic::reframe(const char cor, const char tb, const char sd) {
left->reframe(cor, tb, sd);
right->reframe(cor, tb, sd);
}

//接口类
class Picture{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);
friend Picture hcat(const Picture& , const Picture& );
friend Picture vcat(const Picture&, const Picture&);
friend std::ostream& operator<<(std::ostream& , const Picture& );

public:

//从一个装有string类型对象的容器中获得数据
Picture(const std::vector<std::string>& = std::vector<std::string>());
//由于改变了对象的状态
void reframe(const char, const char, const char);
private:
Ptr<Pic_base>p;
//构造函数提供类型转换
Picture(Pic_base* ptr):p(ptr){}


};

void Picture::reframe(const char corner, const char top_bottom, const char side) {
p->reframe(corner, top_bottom, side);
}

Picture frame(const Picture& pic, const char cor, const char tb, const char sd){
return new Frame_Pic(pic.p, cor, tb, sd);

}

Picture frame(const Picture& pic) {
return new Frame_Pic(pic.p);
// Pic_base* temp1 = new Frame_Pic(pic.p);//生成一个新Frame_Pic对象
// Picture temp2(temp1);//使用一个Pic_base*指针构造一个Pictrue类型对象
// return temp2;//返回一个Picture类型对象,这将激活Picture类的复制构造函数
}

Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}

//为vector类型构造Picture类型对象
Picture::Picture(const std::vector<std::string>& v):p(new String_Pic(v)){}

std::ostream& operator<<(std::ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << std::endl;
}
return os;
}

#endif //ACM_PICTURE_H

测试程序:

#include 
#include
#include
#include "Picture.h"

using std::endl; using std::cin;
using std::cout;
using std::string; using std::vector;


int main(int argc, char** argv){
vector<string> v1 = { "one test", "two test", "ohohoh GeeGeeGee" };
Picture p = v1;
Picture q = frame(p);
Picture r = hcat(p, q);
Picture s = vcat(q, r);
Picture t = frame(hcat(s, vcat(r, q)));
cout << t << endl;

t.reframe('*', '*', '*');
cout << t << endl;


return 0;
}

5 重写HCat_Pic类,要求不同大小的子图形在连接时,较小的图形必须在大图形的中间位置与较大图形连接。也就是说,如果水平地连接两个子图形,并且其中一个子图形有4行,而且另一个子图形有两行,那么在输出这个子图形时,要在它的顶上与底下多输出一个空格。注意,这时候某行内存在子图形中的相对号与以前版本有所不同。

重写HCat_Pic的display函数:

void HCat_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
ht_sz left_row = row;
ht_sz right_row = row;
if(left->height() >right->height()){
//计算插入的行数
ht_sz index = (left->height() - right->height())/2;
if(row >= index){
right_row = row - index;//相对于输出图形的行数(在输出图形中有数据的行),而不是实际的行
}else{
right_row = right->height();
}
}else{
ht_sz index = (right->height() - left->height())/2;

left_row = ((row >= index) ? (row - index) : (left->height()));
}
left->display(os, left_row, do_pad || right_row < right->height());//作图后面跟着右图时补齐
right->display(os, right_row, do_pad);

// left->display(os, row, do_pad|| row < right->height());
// right->display(os, row, do_pad);
}

头文件的其他内容其他同上一问。
测试程序:

#include 
#include
#include
#include "Picture.h"

using std::endl; using std::cin;
using std::cout;
using std::string; using std::vector;


int main(int argc, char** argv){
vector<string> v1 = { "Ruminations on C++", "C trap and Pitfalls" };
vector<string> v2 = { "the C++ Programming Language", "Generic Programming and the STL", "Programing Pearls", "The Annotated STL Sources" };

cout << frame(hcat(v1, v2)) << endl;

cout << hcat(v2, v1) << endl;

cout << hcat(frame(v1), v2) << endl;


return 0;
}

6 使用前写的Str类和Vec类实现Picture类,并编程测试。

头文件:
Str.h

//
// Created by MacBook Pro on 2020-03-17.
//

#ifndef ACM_STR_H
#define ACM_STR_H

#include "Vec.h"
#include
#include "Ptr.h"


//模版特化
template<>
inline Vec<char>* clone(const Vec<char>* vp)
{
return new Vec<char>(*vp);
}

class Str{
friend std::istream& operator>>(std::istream&, Str&);
public:
typedef Vec<char>::size_type size_type;
typedef Vec<char>::iterator iterator;
typedef Vec<char>::const_iterator const_iterator;

实现+=运算符(重写)
Str& operator += (const Str& s){
data.make_unique();//新增
std::copy (s.data->begin(), s.data->end(), std::back_inserter(*data));
return *this;
}

默认构造(//全部重写)
Str():data(new Vec<char>){}
//生成一个Str对象,包含c的n个副本
Str(size_type n, char c):data(new Vec<char>(n,c)){}//使用Vec类中的构造函数构造data数据
//生成一个Str对象并使用一个空字符结尾的字符数组来初始化
Str(const char* cp):data(new Vec<char>){
std::copy(cp, cp + std::strlen(cp), std::back_inserter(*data));
}
//生成一个Str对象并使用迭代器b和e之间的内容对他进行初始化
template<class In>Str (In b, In e):data(new Vec<char>){
std::copy(b, e, std::back_inserter(*data));
}

//大小
size_type size() const { return data->size();}

索引(重写)
char& operator[](size_type i) {
data.make_unique();
return (*data)[i];
}
const char &operator[](size_type i) const { return (*data)[i];}

iterator begin() { return data->begin(); };
const_iterator begin() const { return data->begin(); };
iterator end() { return data->end(); };
const_iterator end() const { return data->end(); };

private:
重写
Ptr<Vec<char> > data;//存储指向向量的指针

};
//输入运算符
std::istream& operator>>(std::istream&, Str&);
//输出运算符
std::ostream& operator<<(std::ostream&, const Str&);
//加号运算符
Str operator+(const Str&, const Str&);

//输出运算符定义
std::ostream& operator<<(std::ostream& os, const Str& s){
for (Str::size_type i = 0; i != s.size(); ++i) {
os << s[i];
}
return os;
}
//输入运算符的定义
std::istream& operator>>(std::istream& is, Str& s){
//抹去存在的值(s)
s.data->clear();
//按序读字符并忽略前面的空格字符
char c;
//值进行循环条件,不进行其他工作
while(is.get(c) && isspace(c));
//读入非空白字符
if(is){
do{
s.data->push_back(c);
}while(is.get(c) && !isspace(c));
//如果遇到一空格字符,将它放在输入流的后面
if(is){
is.unget();
}
}
return is;
}

//加号运算符的定义
Str operator+ (const Str& s, const Str& t){
Str r = s;
r += t;
return r;
}
//class Str{
// friend std::istream& operator>>(std::istream&, Str&);
//
//public:
// typedef Vec::size_type size_type;
//
// //实现+=运算符
// Str& operator += (const Str& s){
// std::copy (s.data.begin(), s.data.end(), std::back_inserter(data));
// return *this;
// }
//
// //默认构造
// Str(){}
// //生成一个Str对象,包含c的n个副本
// Str(size_type n, char c):data(n,c){}//使用Vec类中的构造函数构造data数据
// //生成一个Str对象并使用一个空字符结尾的字符数组来初始化
// Str(const char* cp){
// std::copy(cp, cp + std::strlen(cp), std::back_inserter(data));
// }
// //生成一个Str对象并使用迭代器b和e之间的内容对他进行初始化
// templateStr (In b, In e){
// std::copy(b, e, std::back_inserter(data));
// }
//
// //大小
// size_type size() const { return data.size();}
//
// //索引
// char& operator[](size_type i) { return data[i];}
// const char &operator[](size_type i) const { return data[i];}
//
//
//private:
// Vec data;
//
//};
输入运算符
//std::istream& operator>>(std::istream&, Str&);
输出运算符
//std::ostream& operator<<(std::ostream&, const Str&);
加号运算符
//Str operator+(const Str&, const Str&);
//
输出运算符定义
//std::ostream& operator<<(std::ostream& os, const Str& s){
// for (Str::size_type i = 0; i != s.size(); ++i) {
// os << s[i];
// }
// return os;
//}
输入运算符的定义
//std::istream& operator>>(std::istream& is, Str& s){
// //抹去存在的值(s)
// s.data.clear();
// //按序读字符并忽略前面的空格字符
// char c;
// //值进行循环条件,不进行其他工作
// while(is.get(c) && isspace(c));
// //读入非空白字符
// if(is){
// do{
// s.data.push_back(c);
// }while(is.get(c) && !isspace(c));
// //如果遇到一空格字符,将它放在输入流的后面
// if(is){
// is.unget();
// }
// }
// return is;
//}
//
加号运算符的定义
//Str operator+ (const Str& s, const Str& t){
// Str r = s;
// r += t;
// return r;
//}


#endif //ACM_STR_H

Vec.h:

#ifndef Vec_H
#define Vec_H

#include
#include
#include
#include

template<class T> class Vec{
public:
typedef T* iterator;
typedef const T* const_iterator;//迭代器
typedef size_t size_type;//容器长度
typedef T value_type;//值类型
typedef std::ptrdiff_t difference_type;//迭代器相减后的结果
typedef T& reference;//
typedef const T& const_reference;

//构造函数
Vec(){create();}
//可以显示的给val值,也可以使用T的默认构造函数来生成这个值
explicit Vec(std::size_t n, const T& val = T()){create(n, val);}
//复制构造函数
Vec(const Vec& v) { create(v.begin(), v.end());}
//带两个迭代器参数的构造函数
template <class In> Vec(In b, In e){create(b, e);}
//赋值运算符
Vec& operator=(const Vec&);//允许忽略具体类型的名称(因此没有显示声明返回类型名称)
//析构函数
~Vec(){ uncreate();}

//索引(返回引用,是为了避免容器的对象非常大时对它进行复制)
T& operator[](size_type i) { return data[i];}//读写
const T& operator[](size_type i) const { return data[i];}//只读
//动态增加数组
void push_back(const T& t){
if(avail == limit){
grow();
}
unchecked_append(t);
}
//清空
void clear(){
destory();
}
//删除
void erase(iterator pos){
destory(pos);
}
void erase(iterator b , iterator e){
destory(b, e);
}
//出元素
void pop_back(){
pop();
}
//打印数组
std::ostream& print_vec(std::ostream&);
//判断空
bool empty() const{return !data;}

//添加元素:
void insert(iterator it,const T& t){
std::ptrdiff_t dis = it - data;
if(avail == limit) grow();
add(dis, t);
}
template <class In>
void insert(iterator out, In b, In e){
std::ptrdiff_t start = out - data;//插入位置
std::ptrdiff_t dis = e - b;
if(dis > 0){//插入区间合法
const size_type new_length = size() + size_type (dis);
size_type container = limit - data;
while(new_length >= container){
grow();
container = limit - data;
}
add(start, b, e);
}
}
template <class In>
void assign(In, In);

//容器有元素的长度
size_type size() const { return avail - data;}

//返回迭代器类型
iterator begin(){ return data;}//读写
const_iterator begin() const { return data;}//只读

iterator end() { return avail;}
const_iterator end() const { return avail;}

private:
iterator data;//指针指向Vec的第一个元素
iterator avail;//指针指向构造元素后面的一个元素
iterator limit;//指针指向最后一个可获得元素后面的一个元素
//内存分配工具
std::allocator<T> alloc;//控制内存块分配的对象
//为底层的数组分配空间并对它进行初始化
void create();
void create(size_type, const T&);
void create(const_iterator, const_iterator);
template <class In> void create(In, In);
//删除数组中的元素并释放其占有的内存
void uncreate();

//支持push_back函数
void grow();
void unchecked_append(const T&);

//支持clear函数
void destory();

//支持erase函数
iterator destory(iterator);
iterator destory(iterator, iterator);

//支持pop_back
void pop();

//支持insert
void add(std::ptrdiff_t,const T&);
void add(std::ptrdiff_t, const_iterator, const_iterator);

};
//赋值运算符
template<class T> Vec<T>& Vec<T>::operator=(const Vec& rhs){
if(&rhs != this){//this:指向操作数对象的指针
//删除运算符左侧的数组
uncreate();
//从右侧复制元素到左侧
create(rhs.begin(), rhs.end());
}
//返回一个指向表达式做操作数对象的一个引用调用
//该对象生存周期大于赋值操作
//保证了函数返回的时候不被删除
return *this;//返回指向的对象
}
//默认构造
template<class T> void Vec<T>::create() {
data = avail = limit = 0;
}
//带一个参数大小和给初值
template<class T> void Vec<T>::create(size_type n, const T& val){
data = alloc.allocate(n);
limit = avail = data + n;
std::uninitialized_fill(data, limit, val);
}
//带参数大小
template<class T> void Vec<T>::create(const_iterator i, const_iterator j){
data = alloc.allocate(j - i);
limit = avail = std::uninitialized_copy(i, j, data);
}

template <class T>
template <class In>
void Vec<T>::create(In b, In e) {
data = alloc.allocate(e - b);
limit = avail = std::uninitialized_copy(b, e, data);
}

//删除对象,释放占用的内存
template<class T> void Vec<T>::uncreate(){
//alloc.deallocate函数需要一个非零指针作为参数
//既是它不准备释放任何内存
if(data){
//以相反顺序构造函数生成的元素
iterator it = avail;
while(it != data){//删除对象
alloc.destroy(--it);
}
//返回占用的所有内存空间
alloc.deallocate(data, limit - data);//删除未初始化内存
}
//重置指针以表明Vec类型对象为空
data = limit = avail = 0;
}

//push_back函数的成员函数
template<class T> void Vec<T>::grow(){
size_type new_size;
//扩展对象大小时,为对象分配实际使用的两倍大小的内存空间
//Vec为空的时候,选择一个元素进行分配
new_size = std::max(2 * (limit - data), std::ptrdiff_t(1));


//分配新的内存空间并将已存在的对象元素内容复制搭配新内存中
iterator new_data = alloc.allocate(new_size);
iterator new_avail = std::uninitialized_copy(data, avail, new_data);

//返回原来的内存空间
uncreate();

//重置指针,使其指向新分配的内存空间
data = new_data;
avail = new_avail;
limit = data + new_size;
}

//假设avail指向一片新分配的但尚未初始化的内存空间
template<class T> void Vec<T>::unchecked_append(const T& val){
alloc.construct(avail++, val);
}

template <class T>
void Vec<T>::destory() {
iterator it = avail;
while(it != data){
alloc.destroy(--it);
}
avail = data;
}

template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec::iterator pos) {
if(data && pos < avail && pos >= data){
alloc.destroy(pos);
iterator it = pos +1;
while(it != avail){
alloc.construct(pos++, *it++);
alloc.destroy(pos);
}
avail = pos;
}
return avail;
}


template <class T>
typename Vec<T>::iterator Vec<T>::destory(Vec<T>::iterator b, Vec<T>::iterator e) {
if(data && b < e && e < avail && b >= data){
iterator it = b;
while(it != e){
alloc.destroy(it++);
}
while(e != avail){
alloc.construct(b++, *e);
alloc.destroy(e++);
}
avail = b;
}
return avail;
}

template<class T>
std::ostream& Vec<T>::print_vec(std::ostream &os) {
if(avail - data > 0){
const_iterator iter = data;
os << *iter++;
while(iter != avail){
os << " " << *iter++;
}
os << std::endl;
}
return os;
}

template <class T>
void Vec<T>::pop() {
if(data){
alloc.destroy(--avail);
}
}

template <class T>
void Vec<T>::add(std::ptrdiff_t dis, const T& val){
if(dis < avail - data){
iterator e = avail;
iterator b = avail -1;
while(e != data + dis){
alloc.construct(e--, *b--);
alloc.destroy(b);
}
alloc.construct(data + dis, val);
++avail;
}
}

template <class T>
void Vec<T>::add(std::ptrdiff_t start,Vec<T>::const_iterator b, Vec<T>::const_iterator e) {
iterator pos = data + size_type(start);
if(size_type(start)> size()) throw std::domain_error("");

Vec<T>temp;
iterator insert_pos = pos;
for ( ; insert_pos != avail; ++insert_pos) {//原插入位置的后面部分暂存
temp.push_back(*insert_pos);
}

for (const_iterator it = b; it != e; ++it) {//覆盖插入元素
*insert_pos++ = *it;
}

for (const_iterator it = temp.begin(); it != temp.end(); ++it) {//把愿插入位置后面的部分重新插入
*insert_pos++ = *it;
}
//更新avail
avail = insert_pos;


// std::copy(pos, avail, temp);
// std::copy(temp.begin(),temp.end(),std::copy(b, e, pos));

}


template <class T>
template <class In>
void Vec<T>::assign(In b, In e) {
uncreate();
create(b, e);
}
#endif

Picture_c:

//
// Created by MacBook Pro on 2020-03-20.
//

#ifndef ACM_PICTURE_C_H
#include
#include "Vec.h"
#include "Str.h"
#include
#include "Ptr.h"

class Picture;

class Pic_base;
//基类
class Pic_base {
friend class String_Pic;
friend class Frame_Pic;
friend class HCat_Pic;
friend class VCat_Pic;
friend class Picture;

friend std::ostream& operator<<(std::ostream& , const Picture& );

typedef Vec<Str>::size_type ht_sz;//高
typedef Vec<Str>::size_type wd_sz;//宽

//纯虚拟函数
virtual wd_sz width() const = 0;//纯虚拟函数
virtual ht_sz height() const = 0;
virtual void display(std::ostream &, ht_sz, bool) const = 0;//输出内容
virtual void reframe(const char, const char, const char) = 0;
protected:
//静态成员,不属于类的某个对象
//减少定义全局函数或变量
static void pad(std::ostream& os, wd_sz beg, wd_sz end){
while(beg != end){
os <<" ";
++beg;
}
}
public:
//虚拟函数
virtual ~Pic_base(){}
};

//派生类
class String_Pic:public Pic_base{
friend class Picture;

Vec<Str> data;

String_Pic(const Vec<Str>& v):data(v){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char){};
};


Pic_base::ht_sz String_Pic::height() const {
return data.size();
}

Pic_base::wd_sz String_Pic::width() const {
Pic_base::wd_sz n = 0;
for (Pic_base::ht_sz i = 0; i != data.size(); ++i) {
n = std::max(n, data[i].size());
}
return n;
}

void String_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
Pic_base::wd_sz start = 0;
//如果row没有超出范围,就输出第row行
if(row < height()){
os << data[row];
start = data[row].size();
}
//如果有必要,补齐输出各行
if(do_pad){
pad(os, start, width());
}
}

class Frame_Pic:public Pic_base{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);

Ptr<Pic_base> p;
char corner;
char top_bottom;
char side;
//构造函数
// Frame_Pic(const Ptr& pic):p(pic){}
Frame_Pic(const Ptr<Pic_base>& pic, const char corner = '$',
const char top_bottom = '-', const char side = '|')
:p(pic),corner(corner), top_bottom(top_bottom),side(side){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz Frame_Pic::width() const {
return p->width() + 4;
}

Pic_base::ht_sz Frame_Pic::height() const {
return p->height() + 4;
}


void Frame_Pic::display(std::ostream& os, ht_sz row, bool do_pad) const {
if(row >= height()){
//超出范围
if(do_pad){
pad(os, 0, width());
}
}else{
if(row == 0 || row == height() -1){
//最顶行或最低行
os << corner <<std::string(width()-2, top_bottom)<< corner;
}else if(row == 1 || row == height() - 2){
//在第二行或倒数第二行
os << side;
pad(os, 1, width() - 1);
os << side;
}else{
//在内部图形
os << side <<" ";
p->display(os, row - 2, true);
os <<" "<<side;
}
}
}


void Frame_Pic::reframe(const char cor, const char tb, const char sd) {
this->corner = cor;
this->top_bottom = tb;
this->side = sd;

p->reframe(cor, tb, sd);
}
class VCat_Pic:public Pic_base{
friend Picture vcat(const Picture&, const Picture&);

Ptr<Pic_base> top, bottom;
//构造
VCat_Pic(const Ptr<Pic_base>& t, const Ptr<Pic_base>& b):top(t),bottom(b){}
wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz VCat_Pic::width() const {
return std::max(top->width(), bottom->width());
}

Pic_base::ht_sz VCat_Pic::height() const {
return top->height() + bottom->height();
}

void VCat_Pic::display(std::ostream & os, Pic_base::ht_sz row, bool do_pad) const {
wd_sz w = 0;
if(row < top->height()){
//处于上面的子图形中
top->display(os, row, do_pad);
w = top->width();
}else if(row < height()){
//处于下面的子图形中
bottom->display(os, row - top->height(), do_pad);
w = bottom->width();
}
if(do_pad){
pad(os, w, width());
}
}

void VCat_Pic::reframe(const char cor, const char tb, const char sd) {
top->reframe(cor, tb, sd);
bottom->reframe(cor, tb, sd);
}

class HCat_Pic:public Pic_base{
friend Picture hcat(const Picture&, const Picture&);

Ptr<Pic_base>left, right;

HCat_Pic(const Ptr<Pic_base>& l, const Ptr<Pic_base>& r):left(l),right(r){}

wd_sz width() const;
ht_sz height() const;
void display(std::ostream&, ht_sz, bool) const;
void reframe(const char, const char, const char);
};

Pic_base::wd_sz HCat_Pic::width() const {
return left->width() + right->width();
}

Pic_base::ht_sz HCat_Pic::height() const {
return std::max(left->height(), right->height());
}

void HCat_Pic::display(std::ostream &os, Pic_base::ht_sz row, bool do_pad) const {
ht_sz left_row = row;
ht_sz right_row = row;
if(left->height() >right->height()){
//计算插入的行数
ht_sz index = (left->height() - right->height())/2;
if(row >= index){
right_row = row - index;//相对于输出图形的行数(在输出图形中有数据的行),而不是实际的行
}else{
right_row = right->height();
}
}else{
ht_sz index = (right->height() - left->height())/2;

left_row = ((row >= index) ? (row - index) : (left->height()));
}
left->display(os, left_row, do_pad || right_row < right->height());
right->display(os, right_row, do_pad);

// left->display(os, row, do_pad|| row < right->height());
// right->display(os, row, do_pad);
}

void HCat_Pic::reframe(const char cor, const char tb, const char sd) {
left->reframe(cor, tb, sd);
right->reframe(cor, tb, sd);
}

//接口类
class Picture{
friend Picture frame(const Picture&);
friend Picture frame(const Picture&, const char, const char, const char);
friend Picture hcat(const Picture& , const Picture& );
friend Picture vcat(const Picture&, const Picture&);
friend std::ostream& operator<<(std::ostream& , const Picture& );

public:

//从一个装有string类型对象的容器中获得数据
Picture(const Vec<Str>& = Vec<Str>());
//由于改变了对象的状态
void reframe(const char, const char, const char);
private:
Ptr<Pic_base>p;
//构造函数提供类型转换
Picture(Pic_base* ptr):p(ptr){}


};

void Picture::reframe(const char corner, const char top_bottom, const char side) {
p->reframe(corner, top_bottom, side);
}

Picture frame(const Picture& pic, const char cor, const char tb, const char sd){
return new Frame_Pic(pic.p, cor, tb, sd);

}

Picture frame(const Picture& pic) {
return new Frame_Pic(pic.p);
// Pic_base* temp1 = new Frame_Pic(pic.p);//生成一个新Frame_Pic对象
// Picture temp2(temp1);//使用一个Pic_base*指针构造一个Pictrue类型对象
// return temp2;//返回一个Picture类型对象,这将激活Picture类的复制构造函数
}

Picture hcat(const Picture& l, const Picture& r){
return new HCat_Pic(l.p, r.p);
}
Picture vcat(const Picture& t, const Picture& b){
return new VCat_Pic(t.p, b.p);
}

//为vector类型构造Picture类型对象
Picture::Picture(const Vec<Str>& v):p(new String_Pic(v)){}

std::ostream& operator<<(std::ostream& os, const Picture& picture){
const Pic_base::ht_sz ht = picture.p->height();
for (Pic_base::ht_sz i = 0; i != ht; ++i) {
picture.p->display(os, i, false);
os << std::endl;
}
return os;
}



#endif //ACM_PICTURE_C_H

测试程序:

#include 
#include
#include
#include "Picture_c.h"
#include "Vec.h"
#include "Str.h"

using std::endl; using std::cin;
using std::cout;
using std::string; using std::vector;


int main(int argc, char** argv){
Vec<Str> v1;
v1.push_back("i love U");
v1.push_back("U love me");
v1.push_back("how about you");

Picture p = v1;
Picture q = frame(p);
Picture r = hcat(p, q);
Picture s = vcat(q, r);
cout << frame(hcat(s, vcat(r, q))) << endl;


return 0;
}

举报

相关推荐

0 条评论