C++ Primer Plus 第六版 第十三章课后编程练习答案

1.

首先,对于将题中基类修改为虚函数版本,我们只需要将基类的公有函数部分除构造函数和友元之外的函数,声明时前面加上关键字virtual即可;然后对于派生类,我们在私有成员里面添加一个char数组,然后将继承的函数写出来即可。

cd.h

#ifndef CD_H
#define CD_H
#include <iostream>
using namespace std;
class Cd{
    char performers[50];
    char label[20];
    int selections;
    double playtime;
public:
    Cd(char * s1, char * s2, int n, double x);
    Cd(const Cd & d);
    Cd();

    virtual ~Cd();
    virtual void Report() const ;
    virtual Cd &operator=(const Cd & d);
};

class Classic : public Cd
{
    char mainworks[50];//添加一组char成员,用于存储指出CD中主要作品的字符串
public:
    Classic(char * s0, char * s1, char * s2, int n, double x);
    Classic(char * s0, Cd & rs);
    Classic();
    virtual ~Classic();
    virtual void Report() const ;
    virtual Classic &operator=(const Classic & d);
};

#endif

cd.cpp

#include "cd.h"
#include <iostream>
using namespace std;
#include <cstring>

Cd::Cd(char *s1, char *s2, int n, double x)
{
    strcpy_s(performers, 50, s1);
    strcpy_s(label, 20, s2);
    selections = n;
    playtime = x;
}

Cd::Cd()
{
    strcpy_s(performers, 50, "null");
    strcpy_s(label, 20, "null");
    selections = 0;
    playtime = 0;
}

Cd::~Cd()
{}

void Cd ::Report() const
{
    cout << "In this CD disk, the performrs are " << performers << endl;
    cout << "The labels are " << label << endl;
    cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}

Cd & Cd::operator=(const Cd & d)
{
    strcpy_s(performers, 50, d.performers);
    strcpy_s(label, 20, d.label);
    selections = d.selections;
    playtime = d.playtime;
    return *this;
}

Classic::Classic(char *s0, char *s1, char *s2, int n, double x)
: Cd(s1, s2, n, x)
{
    strcpy_s(mainworks, 50, s0);
}

Classic::Classic(char *s0, Cd &rs)
: Cd(rs)
{
    strcpy_s(mainworks, 50, s0);
}

Classic::Classic()
: Cd()
{
    strcpy_s(mainworks, 50, "null");
}

Classic::~Classic()
{}

void Classic::Report() const
{
    Cd::Report();
    cout << "The main works of this disk are " << mainworks << endl;
}

Classic & Classic::operator=(const Classic & d)
{
    if(this == &d)
        return *this;
    Cd::operator=(d);
    strcpy_s(mainworks, 50, d.mainworks);
    return *this;
}

play.cpp

//检测文件按题目即可
#include <iostream>
using namespace std;
#include "cd.h"
void Bravo(const Cd & disk);
int main()
{
    Cd c1("Beatles", "Capitol", 14, 35.5);
    Classic c2 = Classic("Piano Sonata in B flat, Fantasia 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: ";
    Classic copy;
    copy = c2;
    copy.Report();

    return 0;
}

void Bravo(const Cd & disk)
{
    disk.Report();
}

2.

练习1中,我们的成员变量的类型是使用的char数组,本题要求我们改为动态内存分配,所以成员变量的类型我们可以选为char指针,那么这里最最需要注意的就是,这样改过之后,析构函数就必须要发挥作用了,析构函数内部就必须要把构造函数里面初始化时动态分配的内存给delete掉。

cd.h

#ifndef CD_H
#define CD_H
#include <iostream>
using namespace std;
class Cd{
    char * performers;
    char * label;
    int selections;
    double playtime;
public:
    Cd(char * s1, char * s2, int n, double x);
    Cd(const Cd & d);
    Cd();

    virtual ~Cd();
    virtual void Report() const ;
    virtual Cd &operator=(const Cd & d);
};

class Classic : public Cd
{
    char * mainworks;//添加一组char成员,用于存储指出CD中主要作品的字符串
public:
    Classic(char * s0, char * s1, char * s2, int n, double x);
    Classic(char * s0, Cd & rs);
    Classic();
    virtual ~Classic();
    virtual void Report() const ;
    virtual Classic &operator=(const Classic & d);
};

#endif

接下来对于实现文件呢,一方面注意构造函数内部初始化时,都必须首先进行动态内存分配,然后才可以进行strcpy_s函数的赋值,另一方面就是析构函数必须把构造函数里面动态分配的内存都删掉。其他内容不需要改变。

cd.cpp

#include "cd.h"
#include <iostream>
using namespace std;
#include <cstring>

Cd::Cd(char *s1, char *s2, int n, double x)
{
    performers = new char [strlen(s1) + 1];//注意构造函数内部初始化时,都必须首先进行动态内存分配,然后才可以进行strcpy_s函数的赋值
    strcpy_s(performers, strlen(s1) + 1, s1);
    label = new char [strlen(s2) + 1];
    strcpy_s(label, strlen(s2) + 1, s2);
    selections = n;
    playtime = x;
}

Cd::Cd()
{
    performers = new char [5];
    strcpy_s(performers, 5, "null");
    label = new char [5];
    strcpy_s(label, 5, "null");
    selections = 0;
    playtime = 0;
}

Cd::~Cd()
{
    delete [] performers;//析构函数必须把构造函数里面动态分配的内存都删掉
    delete [] label;
}

void Cd ::Report() const
{
    cout << "In this CD disk, the performrs are " << performers << endl;
    cout << "The labels are " << label << endl;
    cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}

Cd & Cd::operator=(const Cd & d)
{
    performers = new char [strlen(d.performers) + 1];
    strcpy_s(performers, strlen(d.performers) + 1, d.performers);
    label = new char [strlen(d.label) + 1];
    strcpy_s(label, strlen(d.label) + 1, d.label);
    selections = d.selections;
    playtime = d.playtime;
    return *this;
}

Classic::Classic(char *s0, char *s1, char *s2, int n, double x)
: Cd(s1, s2, n, x)
{
    mainworks = new char [strlen(s0) + 1];
    strcpy_s(mainworks, strlen(s0) + 1, s0);
}

Classic::Classic(char *s0, Cd &rs)
: Cd(rs)
{
    mainworks = new char [strlen(s0) + 1];
    strcpy_s(mainworks, strlen(s0) + 1, s0);
}

Classic::Classic()
: Cd()
{
    mainworks = new char [5];
    strcpy_s(mainworks, 5, "null");
}

Classic::~Classic()
{
    delete [] mainworks;
}

void Classic::Report() const
{
    Cd::Report();
    cout << "The main works of this disk are " << mainworks << endl;
}

Classic & Classic::operator=(const Classic & d)
{
    if(this == &d)
        return *this;
    Cd::operator=(d);
    mainworks = new char [strlen(d.mainworks) + 1];
    strcpy_s(mainworks, strlen(d.mainworks) + 1, d.mainworks);
    return *this;
}

检测文件不变,同上题。

3.

本题要求在DMA类的基础上进行修改,将三个类统一改为从一个基类ABC派生而来。这里要求使用ABC类指针数组并让用户决定创建的对象类型,即需要做一个交互;同时添加一个View方法用于数据显示,并要求该方法为虚函数。本来lacksDMA类和hasDMA类就是派生于baseDMA类的,所以我们只需使baseDMA类派生于ABC类即可,另外在每个类内部添加一个View方法。


dma.h

#ifndef DMA_H
#define DMA_H
#include <iostream>
using namespace std;

class ABC{
public:
    ABC();
    ~ABC();
    virtual void View() = 0;//题要求在类定义中添加virtual View()方法以处理数据显示
};

class baseDMA : public ABC
{
    char * label;
    int rating;
public:
    baseDMA(const char * l = "null", int r = 0);
    baseDMA(const baseDMA & rs);
    virtual ~baseDMA();
    baseDMA &operator=(const baseDMA & rs);
    friend ostream &operator<< (ostream & os, const baseDMA & rs);
    virtual void View();
};

class lacksDMA : public baseDMA
{
    enum {COL_LEN = 40};
    char color[COL_LEN];
public:
    lacksDMA(const char * c = "blank", const char * l = "null", int r = 0);
    lacksDMA(const char * c, const baseDMA & rs);
    friend ostream &operator<<(ostream & os, const lacksDMA & rs);
    virtual void View();
};

class hasDMA : public baseDMA
{
    char * style;
public:
    hasDMA(const char * s = "none", const char * l = "null", int r = 0);
    hasDMA(const char * s, const baseDMA & rs);
    hasDMA(const hasDMA & hs);
    ~hasDMA();
    hasDMA &operator=(const hasDMA & rs);
    friend ostream  &operator<< (ostream & os, const hasDMA & rs);
    virtual void View();
};

#endif

对于实现文件,几乎与书上的程序清单13.15相同,添加了View方法,在baseDMA类的View方法主要是显示label和rating,而lacksDMA类的View方法新增显示color,hasDMA类的View方法新增显示style。

dma.cpp

#include "dma.h"
using namespace std;
#include <iostream>
#include <string>

ABC::ABC()
{}

ABC::~ABC()
{}

baseDMA::baseDMA(const char * l, int r)
{
    label = new char[strlen(l) + 1];
    strcpy_s(label, strlen(l) + 1, l);
    rating = r;
}

baseDMA::baseDMA(const baseDMA &rs)
{
    label = new char [strlen(rs.label) + 1];
    strcpy_s(label, strlen(rs.label) + 1, rs.label);
    rating = rs.rating;
}

baseDMA::~baseDMA()
{
    delete [] label;
}

baseDMA & baseDMA::operator=(const baseDMA & rs)
{
    if(this == &rs)
        return *this;
    delete [] label;
    label = new char [strlen(rs.label) + 1];
    strcpy_s(label, strlen(rs.label) + 1, rs.label)
    rating = rs.rating;
    return *this;
}

ostream &operator<<(ostream & os, const baseDMA & rs)
{
    os << "Label: " << rs.label << endl;
    os << "Rating: " << rs.rating << endl;
    return os;
}

void baseDMA::View()
{
    cout << "Label: " << label << endl;
    cout << "Rating: " << rating << endl;
}

lacksDMA::lacksDMA(const char *c, const char *l, int r) : baseDMA(l ,r)
{
    strncpy_s(color, 40, c, 39);
    color[39] = '\0';
}

lacksDMA::lacksDMA(const char *c, const baseDMA &rs) : baseDMA(rs)
{
    strncpy_s(color, 40, c, COL_LEN - 1);
    color[COL_LEN - 1] = '\0';
}

ostream &operator<<(ostream & os, const lacksDMA & ls)
{
    os << (const baseDMA &)ls;
    os << "Color: " << ls.color << endl;
    return os;
}

void lacksDMA::View()
{
    baseDMA::View();
    cout << "Color: " << color << endl;
}

hasDMA::hasDMA(const char *s, const char *l, int r) : baseDMA(l, r)
{
    style = new char [strlen(s) + 1];
    strcpy_s(style, strlen(s) + 1, s);
}

hasDMA::hasDMA(const char *s, const baseDMA &rs) : baseDMA(rs)
{
    style = new char [strlen(s) + 1];
    strcpy_s(style, strlen(s) + 1, s);
}

hasDMA::hasDMA(const hasDMA &hs) : baseDMA(hs)
{
    style = new char [strlen(hs.style) + 1];
    strcpy_s(style, strlen(hs.style) + 1, hs.style);
}

hasDMA::~hasDMA()
{
    delete [] style;
}

hasDMA & hasDMA::operator=(const hasDMA & hs)
{
    if(this == &hs)
        return *this;
    baseDMA::operator=(hs);
    delete [] style;
    style = new char[strlen(hs.style) + 1];
    strcpy_s(style, strlen(hs.style) + 1, hs.style);
    return *this;
}

ostream & operator<<(ostream & os, const hasDMA & hs)
{
    os << (const baseDMA &)hs;
    os << "Style: " << hs.style << endl;
    return os;
}

void hasDMA::View()
{
    baseDMA::View();
    cout << "Style: " << style << endl;
}

以下检测文件里,多次使用了cin.ignore()函数,这是因为在每次cin之后,缓冲区内部都会多出一个回车符,导致后面cin.getline()函数执行时,还不等你输入信息,就直接弹出了后面的信息,使用cin.ignore()函数可以有效解决这个问题。

play.cpp

#include "dma.h"
using namespace std;
#include <iostream>

int main()
{
    baseDMA shirt("Portabelly", 8);
    lacksDMA balloon("red", "Blimpo", 4);
    hasDMA map("Mercator", "Buffalo Keys", 5);
    cout << "Displaying baseDMA object:\n";
    cout << shirt << endl;
    cout << "Displaying lackDMA object:\n";
    cout << balloon << endl;
    cout << "Displaying hasDMA object:\n";
    cout << map << endl;
    lacksDMA balloon2(balloon);
    cout << "Result of lackDMA copy:\n";
    cout << balloon2 << endl;
    hasDMA map2;
    map2 = map;
    cout << "Result of hasDMA assignment:\n";
    cout << map2 << endl;
    cout << endl << "Shirt:\n";
    shirt.View();
    cout << endl << "Balloon:\n";
    balloon.View();
    cout << endl << "Map:\n";
    map.View();
    cout << endl << "Balloon2:\n";
    balloon2.View();
    cout << endl << "Map2:\n";
    map2.View();

    cout << "\nHow many inputs: ";
    int number;
    cin >> number;
    cin.ignore();
    for(int i=0; i<number; i++)
    {
        cout << "\n Enter '1' for baseDMA, '2' for lackDMA, '3' for hasDMA: " ;
        char flag;
        while (cin >> flag&& (flag != '1' && flag != '2' && flag != '3'))
        {
            cin.ignore();
            cout << "Enter 1, 2, or 3: ";
        }
        cin.ignore();
        if(flag == '1')
        {
            char *label = new char[20] ;
            int rating;
            cout << "Enter label: ";
            cin.getline(label, 20);
            cout << "Enter rating: ";
            cin >> rating;
            baseDMA * base = new baseDMA(label, rating);
            cout << endl << "Input baseDMA: \n";
            base->View();
        }
        else if (flag == '2')
        {
            char *label = new char[20];
            int rating;
            char *color = new char[40];
            cout << "Enter label: ";
            cin.getline(label, 20);
            cout << "Enter rating: ";
            cin >> rating;
            cin.ignore();
            cout << "Enter color: ";
            cin.getline(color, 40);
            lacksDMA *lacks = new lacksDMA(color, label, rating);
            cout << endl << "Input lacksDMA: \n";
            lacks->View();
        }
        else if (flag == '3')
        {
            char *label = new char[20];
            int rating;
            char *style = new char[40];
            cout << "Enter label: ";
            cin.getline(label, 20);
            cout << "Enter rating: ";
            cin >> rating;
            cin.ignore();
            cout << "Enter style: ";
            cin.getline(style, 40);
            hasDMA *has = new hasDMA(style, label, rating);
            cout << endl << "Input hasDMA: \n";
            has->View();
        }
    }

    return 0;
}

4.

port.h

//直接按题给
#ifndef PORT_H
#define PORT_H
#include <iostream>
using namespace std;
class Port
{
    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);
};

class VintagePort : public Port
{
    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);
    void Show() const ;
    friend ostream &operator<<(ostream & os, const VintagePort & vp);
};

#endif

port.cpp

#include <iostream>
#include "port.h"
using namespace std;
#include <string>

Port::Port(const char *br, const char *st, int b)
{
    brand = new char [strlen(br) + 1];
    strcpy_s(brand, strlen(br) + 1, br);
    strcpy_s(style, 20, st);
    bottles = b;
}

Port::Port(const Port &p)
{
    brand = new char [strlen(p.brand) + 1];
    strcpy_s(brand, strlen(p.brand) + 1, p.brand);
    strcpy_s(style, 20, p.style);
    bottles = p.bottles;
}

Port & Port::operator=(const Port & p)
{
    brand = new char [strlen(p.brand) + 1];
    strcpy_s(brand, strlen(p.brand) + 1, p.brand);
    strcpy_s(style, 20, p.style);
    bottles = p.bottles;
    return *this;
}

Port & Port::operator+=(int b)
{
    bottles += b;
    return *this;
}

Port & Port::operator-=(int b)
{
    bottles -= b;
    return *this;
}

void Port::Show() const
{
    cout << "Brand: " << brand << endl;
    cout << "Style: " << style << endl;
    cout << "Bottles: " << bottles << endl;
}

ostream& operator<<(ostream &os, const Port &p)
{
    os << "Brand: " << p.brand << ", Style: " << p.style << ", Bottles: " << p.bottles << endl;
    return os;
}

VintagePort::VintagePort()
{
    nickname = new char [5];
    strcpy_s(nickname, 5, "none");
    year = 0;
}

VintagePort::VintagePort(const char *br, int b, const char *nn, int y)
{
    nickname = new char [strlen(nn) + 1];
    strcpy_s(nickname, strlen(nn) + 1, nn);
    year = y;
}

VintagePort::VintagePort(const VintagePort &vp)
{
    nickname = new char [strlen(vp.nickname) + 1];
    strcpy_s(nickname, strlen(vp.nickname) + 1, vp.nickname);
    year = vp.year;
}

VintagePort & VintagePort::operator=(const VintagePort & vp)
{
    nickname = new char [strlen(vp.nickname) + 1];
    strcpy_s(nickname, strlen(vp.nickname) + 1, vp.nickname);
    year = vp.year;
    return *this;
}

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;
    os << ", " << vp.nickname << ", " << vp.year;
    return os;
}

play.cpp

#include "port.h"
#include <iostream>
using namespace std;
#include <string>

int main()
{
    Port wine1("Leoardo", "white", 15);
    Port wine2 = wine1;
    cout << "Now your wines: \n";
    wine1.Show();
    wine2.Show();
    wine1+= 18;
    wine2 -= 6;
    cout << "After the change, your wine's bottles: \n";
    cout << "Wine1: ";
    wine1.BottleCount();
    cout << "Wine2: ";
    wine2.BottleCount();
    cout << "And conclusion: \n";
    cout << wine1 << endl;
    cout << wine2 << endl;
    cout << endl;
    cout << "Now your wines upgrade to VintagePort class.\n";
    VintagePort wine3("Elma", 21, "tww", 23);
    VintagePort wine4;
    (Port &)wine4 = (Port &)wine3;
    (VintagePort &)wine4 = (VintagePort &)wine3;
    cout << "Now the new wines are:\n";
    wine3.Show();
    wine4.Show();
    wine3 += 17;
    wine4 -= 5;
    cout << "After the change, new wines' bottles:\n";
    cout << "Wine3: ";
    wine3.BottleCount();
    cout << "Wine4: ";
    wine4.BottleCount();
    cout << "Conclusion: \n";
    cout << wine3 << endl;
    cout << wine4 << endl;
    cout << endl;

    return 0;
}

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值