C++ Primer Plus章节编程练习第十三章

1

题目

  以下面的类声明为基础:

class Cd{
private:
    char performers[50];
    char label[20];
    int selections;
    double playtime;
public:
    Cd(const char* s1,const char* s2,int n,double x);
    Cd(const Cd&d);
    Cd();
    virtual ~Cd(){};
    virtual void Report()const;
    Cd& operator=(const Cd&d);
};

  派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。修改上述声明,使基类的所有函数都是虚的,如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:

void Bravo(const Cd &disk);
int main(){
    Cd c1("Beatles","Capitol",14,35.5);
    Classic c2=Classic("Piano Sonata in B flat","Fantasiz in C","Alfred Brendel","Philips",2,57.17);
    Cd *pcd=&c1;
    cout<<"Using object directly:\n";
    c1.Report();
    c2.Report();
    cout<<"Using type cd *pointer to objects:\n";
    pcd->Report();
    pcd=&c2;
    pcd->Report();
    cout<<"Calling a function with a Cd reference argument:\n";
    Bravo(c1);
    Bravo(c2);
    cout<<"Testing assignment: \n";
    Classic copy;
    copy=c2;
    copy.Report();
    return 0;
}
void Bravo(const Cd& disk){
    disk.Report();
}

题解

#include<iostream>
#include<cstring>
using namespace std;
//题目给出的基类
//******************基类Cd的声明******************
class Cd{
private:
    char performers[50];
    char label[20];
    int selections;
    double playtime;
public:
    Cd(const char* s1,const char* s2,int n,double x);
    Cd(const Cd&d);
    Cd();
    virtual ~Cd(){};
    virtual void Report()const;
    Cd& operator=(const Cd&d);
};
//******************基类Cd的实现******************
Cd::Cd(){
    performers[0]=label[0]='\0';
    selections=0;
    playtime=0;
}
Cd::Cd(const char* s1,const char* s2,int n,double x){
    strncpy(performers,s1,49); performers[49]='\0';
    strncpy(label,s2,19);   label[19]='\0';
    selections=n;
    playtime=x;
}
Cd::Cd(const Cd&d){
    strcpy(performers,d.performers);
    strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
}
void Cd::Report()const{
    cout<<"Performers: "<<performers<<endl;
    cout<<"Label: "<<label<<endl;
    cout<<"Selection: "<<selections<<endl;
    cout<<"Playtime: "<<playtime<<endl;
}
Cd& Cd::operator=(const Cd& d){
    if(this==&d) return *this;
    strcpy(performers,d.performers);
    strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
    return *this;
}

//******************派生类Classic的声明******************
class Classic:public Cd{
private:
    char* contions[2];
public:
    Classic();
    Classic(const char* s1,const char* s2,const char* ch1,
            const char* ch2,int n,double x);
    ~Classic();
    Classic& operator=(const Classic &cl);
    virtual void Report()const;

};
//******************派生类Classic的实现******************
Classic::Classic(){             //自动调用基类的默认构造函数
    for(int i=0;i<2;i++)
        contions[i]=nullptr;    //初始化为空
}
Classic::Classic(const char* s1,const char* s2,const char* ch1,
        const char* ch2,int n,double x):Cd(ch1,ch2,n,x){
    contions[0]=new char[strlen(s1)+1];
    strcpy(contions[0],s1);
    contions[1]=new char[strlen(s2)+1];
    strcpy(contions[1],s2);
}
Classic::~Classic(){
    for(int i=0;i<2;i++)
        delete[] contions[i];
}
Classic& Classic::operator=(const Classic &cl){
    if(this==&cl) return *this;
    Cd::operator=(cl);                      //先对基类赋值
    for(int i=0;i<2;i++){                   //深层赋值
        delete[] contions[i];
        contions[i]=new char[strlen(cl.contions[i])+1];
        strcpy(contions[i],cl.contions[i]);
    }
    return *this;
}
void Classic::Report()const{
    for(int i=0;i<2;i++)
        cout<<"Contions # "<<i+1<<": "<<contions[i]<<endl;
    Cd::Report(); 
}

//******************题目测试函数******************
void Bravo(const Cd &disk);
int main(){
    Cd c1("Beatles","Capitol",14,35.5);
    Classic c2=Classic("Piano Sonata in B flat","Fantasiz in C","Alfred Brendel","Philips",2,57.17);
    Cd *pcd=&c1;
    cout<<"Using object directly:\n";
    c1.Report();
    c2.Report();
    cout<<"Using type cd *pointer to objects:\n";
    pcd->Report();
    pcd=&c2;
    pcd->Report();
    cout<<"Calling a function with a Cd reference argument:\n";
    Bravo(c1);
    Bravo(c2);
    cout<<"Testing assignment: \n";
    Classic copy;
    copy=c2;
    copy.Report();
    return 0;
}
void Bravo(const Cd& disk){
    disk.Report();
}

2

题目

  完成练习1,但让两个类使用动态内存分配而不是长度固定的数组来记录字符串。

题解

#include<iostream>
#include<cstring>
using namespace std;
//题目给出的基类
//******************基类Cd的声明******************
class Cd{
private:
    char *performers;
    char *label;
    int selections;
    double playtime;
public:
    Cd(const char* s1,const char* s2,int n,double x);
    Cd(const Cd&d);
    Cd();
    virtual ~Cd();
    virtual void Report()const;
    Cd& operator=(const Cd&d);
};
//******************基类Cd的实现******************
Cd::Cd(){
    performers=label=nullptr;
    selections=0;
    playtime=0;
}
Cd::Cd(const char* s1,const char* s2,int n,double x){
    performers=new char[strlen(s1)+1];
    strcpy(performers,s1);
    label=new char[strlen(s2)+1];
    strcpy(label,s2);
    selections=n;
    playtime=x;
}
Cd::Cd(const Cd&d){
    performers=new char[strlen(d.performers)+1];
    strcpy(performers,d.performers);
    label=new char[strlen(d.label)+1];
    strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
}
Cd::~Cd(){
    delete[]  performers;
    delete[]  label;
}
void Cd::Report()const{
    cout<<"Performers: "<<performers<<endl;
    cout<<"Label: "<<label<<endl;
    cout<<"Selection: "<<selections<<endl;
    cout<<"Playtime: "<<playtime<<endl;
}
Cd& Cd::operator=(const Cd& d){
    if(this==&d) return *this;
    delete[] performers;
    performers=new char[strlen(d.performers)+1];
    strcpy(performers,d.performers);
    delete[] label;
    label=new char[strlen(d.label)+1];
    strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
    return *this;
}

//******************派生类Classic的声明******************
class Classic:public Cd{
private:
    char* contions[2];
public:
    Classic();
    Classic(const char* s1,const char* s2,const char* ch1,
            const char* ch2,int n,double x);
    ~Classic();
    Classic& operator=(const Classic &cl);
    virtual void Report()const;

};
//******************派生类Classic的实现******************
Classic::Classic(){             //自动调用基类的默认构造函数
    for(int i=0;i<2;i++)
        contions[i]=nullptr;    //初始化为空
}
Classic::Classic(const char* s1,const char* s2,const char* ch1,
        const char* ch2,int n,double x):Cd(ch1,ch2,n,x){
    contions[0]=new char[strlen(s1)+1];
    strcpy(contions[0],s1);
    contions[1]=new char[strlen(s2)+1];
    strcpy(contions[1],s2);
}
Classic::~Classic(){
    for(int i=0;i<2;i++)
        delete[] contions[i];
}
Classic& Classic::operator=(const Classic &cl){
    if(this==&cl) return *this;
    Cd::operator=(cl);                      //先对基类赋值
    for(int i=0;i<2;i++){                   //深层赋值
        delete[] contions[i];
        contions[i]=new char[strlen(cl.contions[i])+1];
        strcpy(contions[i],cl.contions[i]);
    }
    return *this;
}
void Classic::Report()const{
    for(int i=0;i<2;i++)
        cout<<"Contions # "<<i+1<<": "<<contions[i]<<endl;
    Cd::Report(); 
}

//******************题目测试函数******************
void Bravo(const Cd &disk);
int main(){
    Cd c1("Beatles","Capitol",14,35.5);
    Classic c2=Classic("Piano Sonata in B flat","Fantasiz in C","Alfred Brendel","Philips",2,57.17);
    Cd *pcd=&c1;
    cout<<"Using object directly:\n";
    c1.Report();
    c2.Report();
    cout<<"Using type cd *pointer to objects:\n";
    pcd->Report();
    pcd=&c2;
    pcd->Report();
    cout<<"Calling a function with a Cd reference argument:\n";
    Bravo(c1);
    Bravo(c2);
    cout<<"Testing assignment: \n";
    Classic copy;
    copy=c2;
    copy.Report();
    return 0;
}
void Bravo(const Cd& disk){
    disk.Report();
}

3

题目

  修改baseDMA-lacksDMA-hasDMA类层次,让三个类都从一个ABC类派生而来,然后使用与程序清单13.10相似的程序对结果进行测试。也就是说,它应使用ABC指针数组,并让用户决定要创建的对象类型,在类定义中添加virtual View()方法以处理数据显示。

题解

#include<iostream>
#include<cstring>
using namespace std;
//*********************抽象基类AcctABC的声明*********************
class AcctABC{
private:
    char *label;
    double price;
public:
    AcctABC();
    AcctABC(const char *l,double p);
    AcctABC(const AcctABC& abc);
    virtual ~AcctABC(){delete[] label;}
    virtual void View()const=0;
    AcctABC& operator=(const AcctABC& abc);
};
//*********************抽象基类AcctABC的实现*********************
AcctABC::AcctABC(){
    label=nullptr;
    price=0;
}
AcctABC::AcctABC(const char *l,double p){
    label=new char[strlen(l)+1];
    strcpy(label,l);
    price=p;
}
AcctABC::AcctABC(const AcctABC& abc){
    label=new char[strlen(abc.label)+1];
    strcpy(label,abc.label);
    price=abc.price;
}
AcctABC& AcctABC::operator=(const AcctABC& abc){
    if(this==&abc) return *this;
    delete[] label;
    label=new char[strlen(abc.label)+1];
    strcpy(label,abc.label);
    price=abc.price;
    return *this;
}
void AcctABC::View()const{
    cout<<"Label: "<<label<<std::endl;
    cout<<"Price: "<<price<<std::endl;
}

//第一个派生类
//*********************派生类baseDMA的声明*********************
class baseDMA:public AcctABC{
private:
    int rating;
public:
    baseDMA(const char* l="null",double p=0.0,int r=0);
    baseDMA(const baseDMA &rs);
    virtual ~baseDMA(){};
    virtual void View()const;
    baseDMA& operator=(const baseDMA &rs);
};
//*********************派生类baseDMA的实现*********************
baseDMA::baseDMA(const char* l,double p,int r):AcctABC(l,p){
    rating=r;
}
baseDMA::baseDMA(const baseDMA &rs):AcctABC(rs){
    rating=rs.rating;
}
void baseDMA::View()const{                              //cosnt函数中不能调用非const函数,所以getLable()需要是const
    AcctABC::View();
    cout<<"Rating: "<<rating<<std::endl;
}
baseDMA& baseDMA::operator=(const baseDMA &rs){
    if(this==&rs) return *this;
    AcctABC::operator=(rs);
    rating=rs.rating;
    return *this;
}

//*********************派生类lacksDMA的声明*********************
//无动态内存分配
class lacksDMA:public AcctABC{
private:
    enum{COL_LEN=40};
    char color[COL_LEN];
public:
    lacksDMA(const char* c="black",const char* l="null",double p=0.0);
    lacksDMA(const lacksDMA& ls);
    virtual ~lacksDMA(){}
    virtual void View()const;
    lacksDMA& operator=(const lacksDMA& ls);
};
//*********************派生类lackDMA的实现*********************
lacksDMA::lacksDMA(const char* c,const char* l,double p):AcctABC(l,p){
    std::strncpy(color,c,39);
    color[39]='\0';
}
lacksDMA::lacksDMA(const lacksDMA& ls):AcctABC(ls){
    std::strncpy(color,ls.color,COL_LEN-1);
    color[COL_LEN-1]='\0';
}
lacksDMA& lacksDMA::operator=(const lacksDMA& ls){
    if(this==&ls) return *this;
    AcctABC::operator=(ls);
    std::strncpy(color,ls.color,COL_LEN-1);
    color[COL_LEN-1]='\0';
    return *this;
}
void lacksDMA::View()const{
    AcctABC::View();
    cout<<"Color: "<<color<<std::endl;
}

//*********************派生类hasDMA的声明*********************
//有动态内存分配
class hasDMA:public AcctABC{
private:
    char* style;
public:
    hasDMA(const char* s="none",const char* l="null",double p=0.0);
    hasDMA(const hasDMA&hs);
    virtual ~hasDMA();
    hasDMA& operator=(const hasDMA &hs);
    virtual void View()const;
};
//*********************派生类hasDMA的实现*********************
hasDMA::hasDMA(const char* s,const char* l,double p):AcctABC(l,p){
    style=new char[std::strlen(s)+1];
    std::strcpy(style,s);
}
hasDMA::hasDMA(const hasDMA& hs):AcctABC(hs){
    style=new char[std::strlen(hs.style)+1];
    std::strcpy(style,hs.style);
}
hasDMA::~hasDMA(){
    delete [] style;
}
hasDMA& hasDMA::operator=(const hasDMA&hs){
    if(this==&hs)   return *this;
    AcctABC::operator=(hs);
    delete[] style;
    style=new char[std::strlen(hs.style)+1];
    std::strcpy(style,hs.style);
    return *this;
}
void hasDMA::View()const{
    AcctABC::View();
    cout<<"Style: "<<style<<std::endl;
}

//*********************测试函数main*********************
const int CNT=5;
int main(){
    AcctABC* pobject[CNT];
    string temp;
    double price;
    char type;
    for(int i=0;i<CNT;i++){
        cout<<"Enter the lable: ";
        getline(cin,temp);
        cout<<"Enter the price: ";
        cin>>price;
        cout<<"Enter 1 for baseDMA, 2 for lacksDMA, or 3 for hasDMA: ";
        while(cin>>type&&(type!='1'&&type!='2'&&type!='3'))
            cout<<"Enter either 1, 2, or 3 : ";   
        while(cin.get()!='\n')
            continue;
        switch(type){
            case '1': { int rating;
                        cout<<"Enter the rating: ";
                        cin>>rating; cin.get();
                        pobject[i]=new baseDMA(temp.c_str(),price,rating); }
                      break;
            case '2': { string color;
                        cout<<"Enter the color: ";
                        getline(cin,color);
                        pobject[i]=new lacksDMA(color.c_str(),temp.c_str(),price); }
                      break;
            case '3': { string style;
                        cout<<"Enter the style: ";
                        getline(cin,style);
                        pobject[i]=new hasDMA(style.c_str(),temp.c_str(),price); }
                      break;
        }
    }
    cout<<endl;
    for(int i=0;i<CNT;i++){
        pobject[i]->View();
        cout<<endl;
    }
    for(int i=0;i<CNT;i++)
        delete pobject[i];
    return 0;
}

4

题目

  Benevoletn Order of Programmers用来维护瓶装葡萄酒。为描述它,BOP Portmaster设置一个Port类,其声明如下:

class Port{
private:
    char* brand;
    char style[20];
    int bottles;
public:
    Port(const char* br="none", const char *st="none",int b=0);
    Port(const Port&p);
    virtual ~Port(){delete[]  brand;}
    Port& operator=(const Port &p);
    Port& operator+=(int b);
    Port& operator-=(int b);
    int BottleCount()const{return bottles;}
    virtual void Show()const;
    friend ostream& operator<<(ostream &os,const Port& p);
};

  show()方法按照下面的格式显示信息(末尾没有换行符):

Brand: Gallo
Kind: tawny
Bottles: 20

  operator<<()函数按照下面的格式显示信息(末尾没有换行符):

Gallo, tawny, 20

  PortMaster完成了Port类的方法定义后派生了VintagePort类,然后被解职——因为不小心将一瓶45度的Cockburn泼到了正在准备烤肉调料的人身上,VintagePort类如下所示:

class VintagePort:public Port{
private:
    char* nickname;
    int year;
public:
    VintagePort();
    VintagePort(const char* br,int b,const char* nn,int y);
    VintagePort(const VintagePort&vp);
    ~VintagePort(){delete[] nickname;}
    VintagePort& operator=(const VintagePort&vp);
    virtual void Show()const;
    friend ostream& operator<<(ostream& os,const VintagePort &vp);
};

  您被指定负责完成VintagePort。
  a.第一个任务是重建Port方法定义,因为前任被开除时销毁了方法定义。
  b.第二个任务是解释为什么有的方法重新定义了,而有些方法没有重新定义。
  c.第三个任务是解释为何没有将operator=()和operator<<()声明为虚的。
  d.第四个任务是提供VintagePort中各个方法的定义。

题解

#include<iostream>
#include<cstring>
using namespace std;
//******************基类的声明******************
class Port{
private:
    char* brand;
    char style[20];
    int bottles;
public:
    Port(const char* br="none", const char *st="none",int b=0);
    Port(const Port&p);
    virtual ~Port(){delete[]  brand;}
    Port& operator=(const Port &p);
    Port& operator+=(int b);
    Port& operator-=(int b);
    int BottleCount()const{return bottles;}
    virtual void Show()const;
    friend ostream& operator<<(ostream &os,const Port& p);
};
//******************基类的实现******************
Port::Port(const char* br, const char *st,int b){
    brand=new char[strlen(br)+1];
    strcpy(brand,br);
    strncpy(style,st,19); style[19]='\0';
    bottles=b;
}
Port::Port(const Port&p){
    brand=new char[strlen(p.brand)+1];
    strcpy(brand,p.brand);
    strncpy(style,p.style,19); style[19]='\0';
    bottles=p.bottles;
}
Port& Port::operator=(const Port &p){
    if(this!=&p) return *this;
    delete[] brand;
    brand=new char[strlen(p.brand)+1];
    strcpy(brand,p.brand);
    strncpy(style,p.style,19); style[19]='\0';
    bottles=p.bottles;
    return *this;
}
Port& Port::operator+=(int b){
    bottles+=b;
}
Port& Port::operator-=(int b){
    if(b>bottles) bottles=0;        //如果超出可减范围,则直接置零
    else bottles-=b;
}
void Port::Show()const{
    cout<<"Brand: "<<brand<<endl;
    cout<<"Kind: "<<style<<endl;
    cout<<"Bottles: "<<bottles<<endl;
}
ostream& operator<<(ostream &os,const Port& p){
    os<<p.brand<<", "<<p.style<<", "<<p.bottles;
}

//******************派生类的声明******************
class VintagePort:public Port{
private:
    char* nickname;
    int year;
public:
    VintagePort();
    VintagePort(const char* br,int b,const char* nn,int y);
    VintagePort(const VintagePort&vp);
    ~VintagePort(){delete[] nickname;}
    VintagePort& operator=(const VintagePort&vp);
    virtual void Show()const;
    friend ostream& operator<<(ostream& os,const VintagePort &vp);
};
//c
//(1)
//重载的赋值运算符不能被继承,因为重载的赋值运算符一般为自身类型赋值为自身类型,
//基类的赋值运算符重载参数为基类的引用,返回值也为基类引用,派生类使用时,无法将基类自动转化为派生类。
//(2)
//operator<<函数是友元函数,不是成员函数,无法继承
//******************派生类的实现******************
VintagePort::VintagePort(){
    nickname=nullptr;
    year=0;
}
VintagePort::VintagePort(const char* br,int b,const char* nn,int y):Port(br,"none",b){
    nickname=new char[strlen(nn)+1];
    strcpy(nickname,nn);
    year=y;
}
VintagePort::VintagePort(const VintagePort&vp):Port(vp){
    nickname=new char[strlen(vp.nickname)+1];
    strcpy(nickname,vp.nickname);
    year=vp.year;
}
VintagePort& VintagePort::operator=(const VintagePort&vp){
    if(this==&vp) return *this;
    Port::operator=(vp);
    delete[] nickname;
    nickname=new char[strlen(vp.nickname)+1];
    strcpy(nickname,vp.nickname);
    year=vp.year;
}
void VintagePort::Show()const{
    Port::Show();
    cout<<"Nickname: "<<nickname<<endl;
    cout<<"Year: "<<year<<endl; 
}
ostream& operator<<(ostream& os,const VintagePort &vp){
    os<<(const Port&)vp<<", "<<vp.nickname<<", "<<vp.year;
}

当珍惜每一片时光~