2021-03-22 C++ Primer Plus 第十三章 类继承 编程练习

编程练习

1.以下面的类声明为基础:

Cd.h

//
// Created by Reza on 2021/3/18.
//

#ifndef CD_CD_H
#define CD_CD_H


class Cd {
private:
    char performance[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;
//    Cd & operator=(const Cd &d);
};

class Classic : public Cd
{
private:
    char work[20];
public:
    Classic(char *s1,char *s2,char *s3,int n,double x);
//    Classic(const Classic &c);
    Classic();
    virtual ~Classic(){};
    virtual void Report() const;
    Classic & operator=(const Classic &c);
};


#endif //CD_CD_H

Cd.cpp

//
// Created by Reza on 2021/3/18.
//

#include "Cd.h"
#include 
#include 

Cd::Cd(char *s1, char *s2, int n, double x) {
//    performance = new char[strlen(s1)+1];
    std::strcpy(performance, s1);
    std::strcpy(label, s2);
    selections = n;
    playtime = x;
}
Cd::Cd() {
    std::strcpy(performance,"None");
    std::strcpy(label,"None");
    selections = 0;
    playtime = 0;
}
Cd::Cd(const Cd &d) {
    std::strcpy(performance,d.performance);
    std::strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
}
void Cd::Report() const {
    std::cout << "performance: " << performance << '\n';
    std::cout << "label: " << label <<'\n';
    std::cout << "selection: " << selections << '\n';
    std::cout << "playtime: " << playtime << "\n";
    
}
//Cd & Cd::operator=(const Cd &d) {
//    if (this == &d)
//        return *this;
//    std::strcpy(performance,d.performance);
//    std::strcpy(label,d.label);
//    selections = d.selections;
//    playtime = d.playtime;
//    return *this;
//}

Classic::Classic(char *s1, char *s2, char *s3, int n, double x) : Cd(s1,s2,n,x)
{
    std::strcpy(work,s3);
}

Classic::Classic() {
    std::strcpy(work,"None");
}

//Classic::Classic(const Classic &c){
//    std::strcpy(work,c.work);
//}
void Classic::Report() const {
    Cd::Report();
    std::cout << "work: " << work <<'\n';
}

Classic & Classic::operator=(const Classic &c) {
    if (this == &c)
        return *this;
    std::strcpy(work,c.work);
    return *this;
}

main.cpp

#include 
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 object:\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,但让两个类使用动态内存分配为不是长度固定的数组来记录字符串。

Cd.h

//
// Created by Reza on 2021/3/18.
//

#ifndef CD_CD_H
#define CD_CD_H

class Cd {
private:
    char *performance;
    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;
//    Cd & operator=(const Cd &d);
};

class Classic : public Cd
{
private:
    char *work;
public:
    Classic(char *s1,char *s2,char *s3,int n,double x);
//    Classic(const Classic &c);
    Classic();
    virtual ~Classic();
    virtual void Report() const;
    Classic & operator=(const Classic &c);
};


#endif //CD_CD_H

Cd.cpp

//
// Created by Reza on 2021/3/18.
//

#include "Cd.h"
#include 
#include 

Cd::Cd(char *s1, char *s2, int n, double x) {
    performance = new char[std::strlen(s1)+1];
    label = new char[std::strlen(s2)+1];
    std::strcpy(performance, s1);
    std::strcpy(label, s2);
    selections = n;
    playtime = x;
}
Cd::Cd() {
    performance = new char[5];
    label = new char[5];
    std::strcpy(performance,"None");
    std::strcpy(label,"None");
    selections = 0;
    playtime = 0;
}

Cd::Cd(const Cd &d) {
    performance = new char[std::strlen(d.performance)+1];
    label = new char[std::strlen(d.label)+1];
    std::strcpy(performance,d.performance);
    std::strcpy(label,d.label);
    selections=d.selections;
    playtime=d.playtime;
}
Cd::~Cd() {
    delete [] performance;
    delete [] label;
}
void Cd::Report() const {
    std::cout << "performance: " << performance << '\n';
    std::cout << "label: " << label <<'\n';
    std::cout << "selection: " << selections << '\n';
    std::cout << "playtime: " << playtime << "\n";

}

//Cd & Cd::operator=(const Cd &d) {
//    if (this == &d)
//        return *this;
//    std::strcpy(performance,d.performance);
//    std::strcpy(label,d.label);
//    selections = d.selections;
//    playtime = d.playtime;
//    return *this;
//}

Classic::Classic(char *s1, char *s2, char *s3, int n, double x) : Cd(s1,s2,n,x)
{
    work = new char [strlen(s3)+1];
    std::strcpy(work,s3);
}

Classic::Classic() {
    work = new char [5];
    std::strcpy(work,"None");
}
Classic::~Classic() {
    delete [] work;
}

//Classic::Classic(const Classic &c){
//    std::strcpy(work,c.work);
//}

void Classic::Report() const {
    Cd::Report();
    std::cout << "work: " << work <<'\n';
}


Classic & Classic::operator=(const Classic &c) {
    if (this == &c)
        return *this;
    Cd::operator=(c);
    delete [] work;
    work = new char (std::strlen(c.work)+1);
    std::strcpy(work,c.work);
    return *this;
}

main.cpp

#include 
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 object:\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();
}

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

DMA.h

// dma.h  -- inheritance and dynamic memory allocation
#ifndef DMA_H_
#define DMA_H_
#include 

//  Base Class Using DMA
class ABC_DMA
{
private:
    char *label;
    int rating;
public:
    ABC_DMA(const char *s1= nullptr,int r1=0);
    ABC_DMA(const ABC_DMA &a);
    virtual ~ABC_DMA(){delete [] label;};
    virtual void View() const;
    ABC_DMA & operator=(const ABC_DMA &a);
    friend std::ostream & operator<<(std::ostream & os,const ABC_DMA &a);
};

class baseDMA: public ABC_DMA
{
private:
public:
    baseDMA(const char *l = "null", int r = 0);
    friend std::ostream & operator<<(std::ostream & os,
                                     const baseDMA & rs);
};

class lacksDMA :public ABC_DMA
{
private:
    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 ABC_DMA & rs);
    virtual void View() const;
    friend std::ostream & operator<<(std::ostream & os,
                                     const lacksDMA & rs);
};

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

#endif

DMA.cpp

//
// Created by Reza on 2021/3/18.
//

#include "DMA.h"
#include 
#include 
ABC_DMA::ABC_DMA(const char *s1, int r1) {
    label = new char [strlen(s1)+1];
    strcpy(label,s1);
    rating=r1;
}

ABC_DMA::ABC_DMA(const ABC_DMA &a) {
    label = new char [strlen(a.label)+1];
    strcpy(label,a.label);
    rating=a.rating;
}
void ABC_DMA::View() const {
    std::cout << "label: " << label <<'\n';
    std::cout << "rating: " << rating << '\n';
}
ABC_DMA & ABC_DMA::operator=(const ABC_DMA &a)
{
    label = new char [strlen(a.label)+1];
    strcpy(label,a.label);
    rating=a.rating;
    return *this;
}
std::ostream & operator<<(std::ostream & os,const ABC_DMA &a)
{
    os << "label: " << a.label << "rating: " << a.rating << '\n';
    return os;
}

// baseDMA methods
baseDMA::baseDMA(const char * l, int r):ABC_DMA(l,r)
{}

std::ostream & operator<<(std::ostream & os, const baseDMA & rs)
{
    os << (const ABC_DMA &)rs;
    return os;
}


// lacksDMA methods
lacksDMA::lacksDMA(const char * c, const char * l, int r)
        : ABC_DMA(c,r)
{
    strcpy(color,l);
}

lacksDMA::lacksDMA(const char * c, const ABC_DMA & rs)
        : ABC_DMA(rs)
{
    strcpy(color,c);
}

void lacksDMA::View() const {
    ABC_DMA::View();
    std::cout << "color: " << color << '\n';
}

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

// hasDMA methods
hasDMA::hasDMA(const char * s, const char * l, int r)
        : ABC_DMA(l, r)
{
    style = new char[std::strlen(s) + 1];
    std::strcpy(style, s);
}

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

hasDMA::hasDMA(const hasDMA & hs)
        : ABC_DMA(hs)  // invoke base class copy constructor
{
    style = new char[std::strlen(hs.style) + 1];
    std::strcpy(style, hs.style);
}

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

void hasDMA::View() const {
    ABC_DMA::View();
    std::cout << style << '\n';
}

hasDMA & hasDMA::operator=(const hasDMA & hs)
{
    if (this == &hs)
        return *this;
    ABC_DMA::operator=(hs);  // copy base portion
    delete [] style;         // prepare for new style
    style = new char[std::strlen(hs.style) + 1];
    std::strcpy(style, hs.style);
    return *this;
}

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

main.cpp

#include 
using namespace std;
#include "DMA.h"

int main() {
    using std::cout;
    using std::endl;
    using std::string;

    char s1[20];
    int rating;
    unsigned int number;

    ABC_DMA *p[4];
    for (int i = 0; i < 4; ++i) {
        cout << "Enter label name: ";
        cin >> s1;
        cout << "Enter rating: ";
        cin >> rating;
        cout << "Enter 1 : baseDMA \n 2 : lackDMA \n  3 :  hasDMA \n to choose DMA: ";
        while (cin >> number&&(number!=1&&number!=2&&number!=3))
            cout << "Please Enter 1/2/3 !";
        if (number == 1)
            p[i] = new baseDMA(s1,rating);
        else if (number==2)
        {
            char color[40];
            cout << "Please enter color:";
            cin >> color;
            p[i] = new lacksDMA(color,s1,rating);
        }
        else if (number==3)
        {
            char style[40];
            cout << "Please enter style:";
            cin >> style;
            p[i] = new hasDMA(style,s1,rating);
        }
    }
    for(int i=0;i<4;i++)
    {
        p[i]->View();
    }
}

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

#include 
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);

};

Vintage类如下所示:

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

a.第一个任务是重新创建Port方法定义,因为前任被开除时销毁了方法定义。

#include "Port.h"
#include 
#include 
Port::Port(const char *br, const char *st, int b) {
    brand = new char [strlen(br)+1];
    strcpy(brand,br);
    strcpy(style,st);
    bottles = b;
}
Port::Port(const Port &p) {
    brand = new char [strlen(p.brand)+1];
    strcpy(brand,p.brand);
    strcpy(style,p.style);
    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);
    strcpy(style,p.style);
    bottles = p.bottles;
}
Port & Port::operator+=(int b) {
    bottles = bottles + b;
}
Port & Port::operator-=(int b) {
    bottles = 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;
    return os;
}

b.第二个任务是解释为什么有的方法重新定义了,而有些没有重新定义。

由于有些方法在派生类中需要添加更多的功能,而有些方法只需要承担基类中的功能。

c.第三个任务是解释为何没有将operator=()和operator()声明为虚的。

因为基类Port与派生类VintagePort中的operator=()和operator()中所包含的参数不一样,而虚函数要求派生类和基类的方法名和参数列表相同。

d.第四个任务是提供VintagePort中各个方法的定义。

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() {
    nickname = nullptr;
    year = 0;
}
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 <

你可能感兴趣的:(2021-03-22 C++ Primer Plus 第十三章 类继承 编程练习)