C + + premier plus (Sixth Edition) Chapter 13 class inheritance programming practice answer

Posted by neomhm on Mon, 03 Jan 2022 05:13:51 +0100

1. Based on the following class declaration:

// base class
class Cd { // repersents a CD disk
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
~Cd();
void Report() const; // reports all CD data
Cd & operator=(const Cd & d);
};
Derive a Classic class and add a set of char members to store a string indicating the main works in the CD. Modify the above declaration so that all functions of the base class are virtual. If a method declared by the above definition is not required, delete it. Use the following procedure to test your product:

// useclassic.cpp -- test the Classic class
// compile with classic.cpp
#include <iostream>
using namespace std;
#include "classic.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();	// use Cd method
	c2.Report();	// use Classic method

	cout << "Using type cd * pointer to objects:\n";
	pcd->Report();	// use Cd method for cd object
	pcd = &c2;
	pcd->Report();	// use Classic method for class object

	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();
}

This problem is not difficult. Since new is not used to allocate dynamic space, there is no need to explicitly copy constructors, destructors and assignment operators. If you want to dynamically bind the Report() function, the function is a virtual keyword, (ps: constructor uses string constant pointer parameter compilation error, which is changed to string pointer) the code is as follows:

// classic.h -- definition of Classic class

#ifndef CLASSIC_H_
#define CLASSIC_H_
// base class
class Cd {  // repersents a CD disk
private:
    char performers[50];
    char label[20];
    int selections;     // number of selections
    double playtime;    // playing time in minutes
public:
    Cd(char * s1, char * s2, int n, double x);
    Cd();
    virtual void Report() const;    // reports all CD data
};

class Classic : public Cd
{
private:
    char song[60];
public:
    Classic(char * fn, char * pf, char * lb, int sel, double pt);
    Classic();
    virtual void Report() const;
};
#endif
// classic.cpp -- methods for Classic class
#include <iostream>
#include <cstring>
#include "classic.h"

// methods of Cd
Cd::Cd(char * s1, char * s2, int n, double x)
{
    strcpy(performers, s1);
    strcpy(label, s2);
    selections = n;
    playtime = x;
}

Cd::Cd()
{
}

void Cd::Report() const
{
    using std::cout;
    using std::endl;
    cout << "Performers: " << performers << endl;
    cout << "Label: " << label << endl;
    cout << "Selections: " << selections << endl;
    cout << "Playtime: " << playtime << endl;
}

// methods of Classic
Classic::Classic(char * fn, char * pf, char * lb, 
        int sel, double pt) : Cd(pf, lb, sel, pt)
{
    strcpy(song, fn);
}

Classic::Classic()
{
}

void Classic::Report() const
{
    std::cout << "Song: " << song << std::endl;
    Cd::Report();
}

The main function test file is given in the title, and the operation results are as follows:

2. Complete exercise 1, but have the two classes record strings using dynamic memory allocation instead of a fixed length array.

This topic turns the static array of exercise 1 into dynamically allocated memory. First modify the data member, and then modify the implementation constructor. Note that the base class destructor should be a virtual destructor, add a copy constructor, assignment operator and function. ps: the copy constructor does not need to free the pointer space, and the assignment operator function does. The code is as follows:

// classic.h -- definition of Classic class

#ifndef CLASSIC_H_
#define CLASSIC_H_
// base class
class Cd {  // repersents a CD disk
private:
    char * performers;
    char * label;
    int selections;     // number of selections
    double playtime;    // playing time in minutes
public:
    Cd(const char * s1, const char * s2, int n, double x);
    Cd(const Cd & d);
    Cd();
    virtual ~Cd();
    virtual void Report() const;    // reports all CD data
    Cd & operator=(const Cd & d);
};

class Classic : public Cd
{
private:
    char * song;
public:
    Classic(const char * sg, const char * pf, const char * lb, int sel, double pt);
    Classic(const Classic & c);
    Classic();
    ~Classic();
    virtual void Report() const;
    Classic & operator=(const Classic & c);
};
#endif
// classic.cpp -- methods for Classic class
#include <iostream>
#include <cstring>
#include "classic.h"

// methods of Cd
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()
{
    performers = new char[1];
    performers[0] = '\0';
    label = new char[1];
    label[0] = '\0';
    selections = 0;
    playtime = 0.0;
}

Cd::~Cd()
{
    delete [] performers;
    delete [] label;
}

void Cd::Report() const
{
    using std::cout;
    using std::endl;
    cout << "Performers: " << performers << endl;
    cout << "Label: " << label << endl;
    cout << "Selections: " << selections << endl;
    cout << "Playtime: " << playtime << endl;
}

Cd & Cd::operator=(const Cd & d)
{
    if (this == &d)
        return *this;
    else
    {
        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;
    }
}

// methods of Classic
Classic::Classic(const char * sg, const char * pf, const char * lb, 
        int sel, double pt) : Cd(pf, lb, sel, pt)
{
    song = new char[strlen(sg) + 1];
    strcpy(song, sg);
}

Classic::Classic(const Classic & c) : Cd(c)
{
    song = new char[strlen(c.song) + 1];
    strcpy(song, c.song);
}

Classic::Classic():Cd()
{
    song = new char[1];
    song[0] = '\0';
}

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

void Classic::Report() const
{
    std::cout << "Song: " << song << std::endl;
    Cd::Report();
}

Classic & Classic::operator=(const Classic & c)
{
    if (this == &c)
        return *this;
    else
    {
        delete [] song;
        song = new char[strlen(c.song) + 1];
        strcpy(song, c.song);
        Cd::operator=(c);
        return *this;
    }
}
// useclassic.cpp -- test the Classic class
// compile with classic.cpp
#include <iostream>
using namespace std;
#include "classic.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();	// use Cd method
	c2.Report();	// use Classic method

	cout << "Using type cd * pointer to objects:\n";
	pcd->Report();	// use Cd method for cd object
	pcd = &c2;
	pcd->Report();	// use Classic method for class object

	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();
}

The operation results are the same as above, which are not provided here.

3. Modify the basedma laksdma hasdma class hierarchy so that all three classes derive from an ABC, and then test the results using a program similar to that in program listing 13.10. That is, it should use an ABC pointer array and let the user decide the type of object to create. Add a virtual View() method to the class definition to handle explicit data.

This problem is to create an abstract class and use the abstract class to derive three concrete classes. An abstract class needs a pure virtual function. Here, use View()=0 to make the defined DMAABC called an abstract class. There is no difficulty in the code here. Ps: when writing the main function, ignore the mixed input of string and number. You need to absorb the newline character of the number and add it get() solution; There is also a mismatch error caused by adding [] when deleting the pointer. The example code for deleting [] is as follows:

// dma.h -- inheritance and dynamic memory allocation
#ifndef DMA_H_
#define DMA_H_
# include <iostream>
// ABC Class using DMA
class DMAABC
{
private:
    char * label;
    int rating;
public:
    DMAABC(const char * l = "null", int r = 0);
    DMAABC(const DMAABC & rda);
    virtual ~DMAABC();
    DMAABC & operator=(const DMAABC & rda);
    virtual void View() const =0;
};

// BaseDMA class definition
class baseDMA : public DMAABC
{
public:
    baseDMA(const char * l = "null", int r = 0) : DMAABC(l, r) { }
    virtual void View() const;
};

// derived class without DMA
// no destructor needed
// uses implicit copy constructor
// uses implicit assignment operator
class lacksDMA : public DMAABC
{
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 baseDMA & rs);
    virtual void View() const;
};

// derived class with DMA
class hasDMA : public DMAABC
{
private:
    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 & hs);
    virtual void View() const;
};
#endif
// dma.cpp -- methods for Class DMAABC
#include <cstring>
#include "dma.h"

// methods for DMAABC class
DMAABC::DMAABC(const char * l, int r)
{
    label = new char[strlen(l) + 1];
    strcpy(label, l);
    rating = r;
}

DMAABC::DMAABC(const DMAABC & rda)
{
    label = new char[strlen(rda.label) + 1];
    strcpy(label, rda.label);
    rating = rda.rating;
}

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

DMAABC & DMAABC::operator=(const DMAABC & rda)
{
    if (this == &rda)
        return *this;
    else
    {
        delete [] label;
        label = new char[strlen(rda.label) + 1];
        strcpy(label, rda.label);
        rating = rda.rating;
        return *this;
    }
}

void DMAABC::View() const
{
    std::cout << "Lable: " << label << std::endl;
    std::cout << "Rating: " << rating << std::endl;
}

// methods for BaseDMA class
void baseDMA::View() const
{
    DMAABC::View();
}

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

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

void lacksDMA::View() const
{
    std::cout << "Color: " << color << std::endl;
    DMAABC::View();
}

// derived class with DMA

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

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

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

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

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

void hasDMA::View() const
{
    std::cout << "Style: " << style << std::endl;
    DMAABC::View();
}
#include "dma.h"
const int MAX = 3;
const int CMAX = 40;

int main()
{
	using std::cin;
    using std::cout;
    using std::endl;
	char temp1[CMAX];
	int tempr;
	char kind;

	DMAABC * p_dma[MAX];

	for(int i = 0; i < MAX; i++)
	{
		cout << "Enter the label: ";
		cin.getline(temp1,CMAX);
		cout << "Enter the rating: ";
		(cin >> tempr).get();
		cout << "Enter 1 for baseDMA or "
			 << "2 for lacksDMA or "
			 << "3 for hasDMA: ";
		while (cin >> kind &&(kind != '1' && kind != '2' && kind != '3'))
        {
            cout << "Enter either 1 or 2 or 3: ";
        }
		while(cin.get() != '\n')
			continue;
		if(kind == '1')
			p_dma[i] = new baseDMA(temp1, tempr);
		else if (kind == '2')
		{
			char temp2[CMAX];
			cout << "Enter the color: ";
			cin.getline(temp2,CMAX);
			p_dma[i] = new lacksDMA(temp2, temp1, tempr);
		}
		else
		{
			char temp2[CMAX];
			cout << "Enter the style: ";
			cin.getline(temp2,CMAX);
			p_dma[i] = new hasDMA(temp2, temp1, tempr);
		}
	}
	cout << endl;
	for(int i = 0; i < MAX; i++)
	{
		p_dma[i]->View();
		cout << endl;
	}

	for(int i = 0; i < MAX; i++)
		delete p_dma[i];
	cout << "Done\n";
	return 0;
}

The operation results are as follows:

4. Benevolent Order of Programmers is used to maintain bottled wine boxes. To describe it, the BOP Portmaster sets a Port class, which is declared as follows:

#include <iostream>
using namespace std;
class Port
{
private:
    char * brand;
    char style[20]; // i.e., tawny, ruby, vintage
    int bottles;
public:
    Port(const char * br = "none", const char * st = "none", int b = 0);
    Port(const Port & p);               // copy constructor
    virtual ~Port() { delete [] brand; }
    Port & operator=(const Port & p);
    Port & operator+=(int b);           // adds b to bottles
    Port & operator-=(int b);           // subtracts b from bottles, if availiable

    int BottleCount() const { return bottles; }
    virtual void Show() const;
    friend ostream & operator<<(ostream & os, const Port & p);
};
The show() method explicitly displays the information in the following format: Brand: Gallo Kind: tawny Bottles: 20 The operator < < () function explicitly displays the information in the following format (there is no newline at the end) Gallo, tawny, 20 After the PortMaster completes the definition of the Port class method, it derives the VintagePort class and is dismissed - because it accidentally spills a bottle of 45 degree Cockburn on the person preparing the barbecue seasoning. The VintagePort class is as follows:
class VintagePort : public Port // style necessarily = "vintage"
{
private:
    char * nickname;            // i.e.,"The Noble" or "Old Velet", etc.
    int year;                   // vintage 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);
};
You are assigned to complete the vintage port. a. In the first task, re create the Port method definition because the method definition was destroyed when the predecessor was dismissed. b. The second task is to explain why some methods have been redefined while others have not. c. The third task is to explain why operator = () and operator < < () are not declared virtual. d. The fourth task is to provide the definition of each method in the vintage port. The answers to questions a and d are in the code file; b. The redefined code is the Show() code, because it is displayed differently in the two classes, as well as the output operator. The output is also different in the two classes. What is not redefined is the method of operating bottles, which is the same for the two classes, so it does not need to be redefined; c. The operator < < () function is not a member function of the Port class, and the virtual function must be a member function. However, the parameters of the two classes of the operator = () function are different, and declaring the virtual function does not have the corresponding effect. The sample code is as follows:
// vintageport.h -- definition for Port class
#ifndef VINTAGEPORT_H_
#define VINTAGEPORT_H_
#include <iostream>
using namespace std;
class Port
{
private:
    char * brand;
    char style[20]; // i.e., tawny, ruby, vintage
    int bottles;
public:
    Port(const char * br = "none", const char * st = "none", int b = 0);
    Port(const Port & p);               // copy constructor
    virtual ~Port() { delete [] brand; }
    Port & operator=(const Port & p);
    Port & operator+=(int b);           // adds b to bottles
    Port & operator-=(int b);           // subtracts b from bottles, if availiable

    int BottleCount() const { return bottles; }
    virtual void Show() const;
    friend ostream & operator<<(ostream & os, const Port & p);
};

class VintagePort : public Port // style necessarily = "vintage"
{
private:
    char * nickname;            // i.e.,"The Noble" or "Old Velet", etc.
    int year;                   // vintage 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);
};
#endif
// vintageport.cpp -- methods for VintagePort class
#include <cstring>
#include "vintageport.h"
// methods for Port class
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;
    else
    {
        delete [] brand;
        brand = new char[strlen(p.brand) + 1];
        strcpy(brand, p.brand);
        strcpy(style, p.style);
        bottles = p.bottles;
        return *this;
    }
}

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

Port & Port::operator-=(int b)
{
    if (b <= bottles)
        bottles -= b;
    else
        cout << b << " > " << bottles << endl;
    return *this;
}

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;
}

// methods for VintagePort class
VintagePort::VintagePort() : Port("none","vintage")
{
    nickname = new char[5];
    strcpy(nickname, "none");
    year = 0;
}

VintagePort::VintagePort(const char * br, int b, const char * nn, int y) : Port(br, "vintage", 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;
    else
    {
        Port::operator=(vp);
        delete [] nickname;
        nickname = new char[strlen(vp.nickname) + 1];
        strcpy(nickname, vp.nickname);
        year = vp.year;
        return *this;
    }
}

void VintagePort::Show() const
{
    Port::Show();
    cout << "Nick Name: " << nickname << endl;
    cout << "Year: " << year << endl;
}

ostream & operator<<(ostream & os, const VintagePort & vp)
{
    os << (const Port &)vp << ", " << vp.nickname << ", " << vp.year;
    return os;
}
// usevintageport.cpp -- test VintagePort class
// compile with vintageport.cpp
#include "vintageport.h"

int main()
{
	Port gal("Gallo", "tawny", 20);
	Port * pp;
	VintagePort vp("Chateau Margaux", 10, "The Noble",1999);
	VintagePort * pvp;
	pp = &vp;
	pvp = &vp;
	cout << "Output with Show():\n";
	pp->Show();
	pp = &gal;
	pp->Show();
	cout << "Take out 30 bottles:\n"; 
	*pp -= 30;
	pp->Show();
	cout << "After add 10 bottles:\n";
	*pp += 10;
	pp->Show();
	pp = &vp;
	cout << "Output with operator<< :\n";
	cout << "Object: " << vp << endl;
	cout << "Pointer Port: " << *pp << endl;
	cout << "Pointer VintagePort: " << *pvp << endl;
	return 0;
}

The operation results are as follows:

Ps: it can be seen from the running results that the friend operator < < function does not have the function of virtual function and cannot output the corresponding content according to the object

Topics: C++