第十三章编程练习

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

class Cd
{
private:
	char performers[50];
	char label[20];
	int selecttions;//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);
};

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

#pragma once
#include <cstring>
#include <iostream>
using namespace std;

//base class
class Cd
{
private:
	char performers[50];
	char label[20];
	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();
	Cd& operator=(const Cd& d);

	virtual ~Cd() {}
	virtual void Report()const;//reports all CD data
};

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

classic.cpp

#include "classic.h"

//base class
Cd::Cd(const char* s1, const char* s2, int n, double x)
{
	strncpy(performers, s1, 50);
	if (strlen(s1) >= 50)
	{
		performers[49] = '\0';
	}
	else
	{
		performers[strlen(s1)] = '\0';
	}

	strncpy(label, s2, 20);
	if (strlen(s2) >= 20)
	{
		label[19] = '\0';
	}
	else
	{
		label[strlen(s2)] = '\0';
	}

	selections = n;
	playtime = x;
}

Cd::Cd(const Cd& d)
{
	strcpy(performers, d.performers);
	strcpy(label, d.label);
	selections = d.selections;
	playtime = d.playtime;
}

Cd::Cd()
{
	performers[0] = '\0';
	label[0] = '\0';
	selections = 0;
	playtime = 0;
}

void Cd::Report() const
{
	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;
	}
	strcpy(performers, d.performers);
	strcpy(label, d.label);
	selections = d.selections;
	playtime = d.playtime;
	return *this;
}

//children class
Classic::Classic() : Cd()
{
	work[0] = '\0';
}

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

Classic::Classic(const char* s1, const char* s2, const char* s3, int n, double x) : Cd(s2,s3 ,n,x)
{
	strncpy(work, s1, 50);
	if (strlen(s1) >= 50)
	{
		work[49] = '\0';
	}
	else
	{
		work[strlen(s1)] = '\0';
	}
}

void Classic::Report() const 
{
	Cd::Report();
	cout << "work:" << work << endl;
}

Classic& Classic::operator=(const Classic& c)
{
	if (this == &c)
	{
		return *this;
	}

	Cd::operator=(c);
	strcpy(work, c.work);
	return *this;
}

main.cpp

#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 classic object

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

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

#pragma once
#include <cstring>
#include <iostream>
using namespace std;

//base class
class Cd
{
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();
	Cd& operator=(const Cd& d);

	virtual ~Cd();
	virtual void Report()const;//reports all CD data
};

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

classic.cpp

#include "classic.h"

//base class
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 = nullptr;
	label = nullptr;
	selections = 0;
	playtime = 0;
}

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

void Cd::Report() const
{
	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;
	}

	delete[]performers;
	delete[]label;

	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;
	return *this;
}

//children class
Classic::Classic() : Cd()
{
	work = nullptr;
}

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

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

void Classic::Report() const 
{
	Cd::Report();
	cout << "work:" << work << endl;
}

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

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

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

#pragma once
#include <iostream>
#include <cstring>
using namespace std;

//Base
class ABC
{
private:
    char* label;
    int rating;

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

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

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

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

dma.cpp

#include "dma.h"
//ABC methods
ABC::ABC(const char* l, int r)
{
    label = new char[std::strlen(l) + 1];
    std::strcpy(label, l);
    rating = r;
}

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

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

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

void ABC::View() const
{
    cout << "label:" << label << endl;
    cout << "rating:" << rating << endl;
}

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

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

baseDMA::baseDMA(const baseDMA& rs) : ABC(rs)
{
}

void baseDMA::View() const 
{
    ABC::View();
}

// lacksDMA methods
lacksDMA::lacksDMA(const char* l, int r, const char* c) : ABC(l, r)
{
    strncpy(color, c, COL_LEN - 1);
    color[COL_LEN - 1] = '\0';
}

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

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

void lacksDMA::View() const
{
    ABC::View();
    cout << "Color:" << color << endl;

}

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

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

hasDMA::hasDMA(const hasDMA& hs) : ABC(hs) // invoke base class copy constructor
{
    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;
    ABC::operator=(hs);     // copy base portion
    delete[] style;         // prepare for new style
    style = new char[strlen(hs.style) + 1];
    strcpy(style, hs.style);
    return *this;
}

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

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

main.cpp

int main()
{
    baseDMA shirt("Portabelly", 8);
    lacksDMA balloon("red", 4, "Blimpo");
    hasDMA map("Mercator", 5, "Buffalo Keys");
    cout << "Displaying baseDMA object:\n";
    cout << shirt << endl;
    cout << "Displaying lacksDMA object:\n";
    cout << balloon << endl;
    cout << "Displaying hasDMA object:\n";
    cout << map << endl;
    lacksDMA balloon2(balloon);
    cout << "Result of lacksDMA copy:\n";
    cout << balloon2 << endl;
    hasDMA map2;
    map2 = map;
    cout << "Result of hasDMA assignment:\n";
    cout << map2 << endl;
    return 0;
}

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

#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
available
    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 // style necessarily = "vintage"
{
private:
    char * nickname;  // i.e., "The Noble" or "Old Velvet", 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);
};

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

实现:
port.h

#pragma once
#include <iostream>
#include <cstring>
using namespace std;

//base 
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 available
    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 Velvet", etc.
    int year;         // vintage year
public:
    VintagePort();
    VintagePort(const char* br, const char* st, 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);
};

port.cpp

#include "port.h"

//Port methods
Port::Port(const char* br, const char* st, int b)
{
	brand = new char[strlen(br) + 1];
	strcpy(brand, br);
	
	strncpy(style, st, 20);
	if (strlen(st) >= 20)
	{
		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, 20);
	if (strlen(p.style) >= 20)
	{
		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, 20);
	if (strlen(p.style) >= 20)
	{
		style[19] = '\0';
	}

	bottles = p.bottles;

	return *this;
}

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

Port& Port::operator-=(int b)
{
	if (bottles <= 0)
	{
		cout << "It's already negative!" << endl;
	}

	bottles -= b;
	return *this;
}

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

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

//VintagePort methods
VintagePort::VintagePort() : Port()
{
	nickname = nullptr;
	year = 0;
}

VintagePort::VintagePort(const char* br, const char* st, int b, const char* nn, int y) : Port(br, st, 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;
	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 << ", Nickname:" << vp.nickname << ", Year:" << vp.year << endl;
	return os;
}

main.cpp

#include "port.h"

int main()
{
    Port port1("ABC", "Sweet", 200);
    cout << port1 << endl;

    cout << endl;

    VintagePort vp("EFG", "Sour", 300, "old jack", 1998);
    cout << vp << endl;

    cout << endl;

    VintagePort vp2(vp);
    cout << vp2 << endl;

    cout << endl;

    Port* p_port;
    p_port = &port1;
    p_port->Show();

    cout << endl;

    p_port = &vp2;
    p_port->Show();

    return 0;
}

回答:
b:BottleCount()没有定义为虚函数,因派生类继承了基类的方法,可以直接用,不需要重新定义。
show()定义为了虚函数,因基类需要显示基类的成员,而派生类不仅需要显示基类的成员,也需要显示自己新增的成员。
c:operator<<()是友元函数,不能继承。
operator=()在基类里赋值的数据是基类的对象,在派生类里赋值的数据是派生类的对象,可以定义为虚函数,但是没意义。

vp2 = port1;//无意义 调用虚函数的左侧得是类对象的指针或引用
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值