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 <cstring>
#include <iostream>

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 <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 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 <cstring>
#include <iostream>

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 <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 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 <iostream>

//  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 <cstring>
#include <iostream>
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 <iostream>
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 <iostream>
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 <iostream>
#include <cstring>
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 <<vp.nickname << ", " << vp.year << ", ";
    return os;
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,039评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,426评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,417评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,868评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,892评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,692评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,416评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,326评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,782评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,957评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,102评论 1 350
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,790评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,442评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,996评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,113评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,332评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,044评论 2 355

推荐阅读更多精彩内容