C++ Primer Plus章节编程练习第十三章
1
题目
以下面的类声明为基础:
class Cd{
private:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(const char* s1,const char* s2,int n,double x);
Cd(const Cd&d);
Cd();
virtual ~Cd(){};
virtual void Report()const;
Cd& operator=(const Cd&d);
};
派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。修改上述声明,使基类的所有函数都是虚的,如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:
void Bravo(const Cd &disk);
int main(){
Cd c1("Beatles","Capitol",14,35.5);
Classic c2=Classic("Piano Sonata in B flat","Fantasiz 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: \n";
Classic copy;
copy=c2;
copy.Report();
return 0;
}
void Bravo(const Cd& disk){
disk.Report();
}
题解
#include<iostream>
#include<cstring>
using namespace std;
//题目给出的基类
//******************基类Cd的声明******************
class Cd{
private:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(const char* s1,const char* s2,int n,double x);
Cd(const Cd&d);
Cd();
virtual ~Cd(){};
virtual void Report()const;
Cd& operator=(const Cd&d);
};
//******************基类Cd的实现******************
Cd::Cd(){
performers[0]=label[0]='\0';
selections=0;
playtime=0;
}
Cd::Cd(const char* s1,const char* s2,int n,double x){
strncpy(performers,s1,49); performers[49]='\0';
strncpy(label,s2,19); label[19]='\0';
selections=n;
playtime=x;
}
Cd::Cd(const Cd&d){
strcpy(performers,d.performers);
strcpy(label,d.label);
selections=d.selections;
playtime=d.playtime;
}
void Cd::Report()const{
cout<<"Performers: "<<performers<<endl;
cout<<"Label: "<<label<<endl;
cout<<"Selection: "<<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;
}
//******************派生类Classic的声明******************
class Classic:public Cd{
private:
char* contions[2];
public:
Classic();
Classic(const char* s1,const char* s2,const char* ch1,
const char* ch2,int n,double x);
~Classic();
Classic& operator=(const Classic &cl);
virtual void Report()const;
};
//******************派生类Classic的实现******************
Classic::Classic(){ //自动调用基类的默认构造函数
for(int i=0;i<2;i++)
contions[i]=nullptr; //初始化为空
}
Classic::Classic(const char* s1,const char* s2,const char* ch1,
const char* ch2,int n,double x):Cd(ch1,ch2,n,x){
contions[0]=new char[strlen(s1)+1];
strcpy(contions[0],s1);
contions[1]=new char[strlen(s2)+1];
strcpy(contions[1],s2);
}
Classic::~Classic(){
for(int i=0;i<2;i++)
delete[] contions[i];
}
Classic& Classic::operator=(const Classic &cl){
if(this==&cl) return *this;
Cd::operator=(cl); //先对基类赋值
for(int i=0;i<2;i++){ //深层赋值
delete[] contions[i];
contions[i]=new char[strlen(cl.contions[i])+1];
strcpy(contions[i],cl.contions[i]);
}
return *this;
}
void Classic::Report()const{
for(int i=0;i<2;i++)
cout<<"Contions # "<<i+1<<": "<<contions[i]<<endl;
Cd::Report();
}
//******************题目测试函数******************
void Bravo(const Cd &disk);
int main(){
Cd c1("Beatles","Capitol",14,35.5);
Classic c2=Classic("Piano Sonata in B flat","Fantasiz 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: \n";
Classic copy;
copy=c2;
copy.Report();
return 0;
}
void Bravo(const Cd& disk){
disk.Report();
}
2
题目
完成练习1,但让两个类使用动态内存分配而不是长度固定的数组来记录字符串。
题解
#include<iostream>
#include<cstring>
using namespace std;
//题目给出的基类
//******************基类Cd的声明******************
class Cd{
private:
char *performers;
char *label;
int selections;
double playtime;
public:
Cd(const char* s1,const char* s2,int n,double x);
Cd(const Cd&d);
Cd();
virtual ~Cd();
virtual void Report()const;
Cd& operator=(const Cd&d);
};
//******************基类Cd的实现******************
Cd::Cd(){
performers=label=nullptr;
selections=0;
playtime=0;
}
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(){
delete[] performers;
delete[] label;
}
void Cd::Report()const{
cout<<"Performers: "<<performers<<endl;
cout<<"Label: "<<label<<endl;
cout<<"Selection: "<<selections<<endl;
cout<<"Playtime: "<<playtime<<endl;
}
Cd& Cd::operator=(const Cd& d){
if(this==&d) return *this;
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;
}
//******************派生类Classic的声明******************
class Classic:public Cd{
private:
char* contions[2];
public:
Classic();
Classic(const char* s1,const char* s2,const char* ch1,
const char* ch2,int n,double x);
~Classic();
Classic& operator=(const Classic &cl);
virtual void Report()const;
};
//******************派生类Classic的实现******************
Classic::Classic(){ //自动调用基类的默认构造函数
for(int i=0;i<2;i++)
contions[i]=nullptr; //初始化为空
}
Classic::Classic(const char* s1,const char* s2,const char* ch1,
const char* ch2,int n,double x):Cd(ch1,ch2,n,x){
contions[0]=new char[strlen(s1)+1];
strcpy(contions[0],s1);
contions[1]=new char[strlen(s2)+1];
strcpy(contions[1],s2);
}
Classic::~Classic(){
for(int i=0;i<2;i++)
delete[] contions[i];
}
Classic& Classic::operator=(const Classic &cl){
if(this==&cl) return *this;
Cd::operator=(cl); //先对基类赋值
for(int i=0;i<2;i++){ //深层赋值
delete[] contions[i];
contions[i]=new char[strlen(cl.contions[i])+1];
strcpy(contions[i],cl.contions[i]);
}
return *this;
}
void Classic::Report()const{
for(int i=0;i<2;i++)
cout<<"Contions # "<<i+1<<": "<<contions[i]<<endl;
Cd::Report();
}
//******************题目测试函数******************
void Bravo(const Cd &disk);
int main(){
Cd c1("Beatles","Capitol",14,35.5);
Classic c2=Classic("Piano Sonata in B flat","Fantasiz 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: \n";
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()方法以处理数据显示。
题解
#include<iostream>
#include<cstring>
using namespace std;
//*********************抽象基类AcctABC的声明*********************
class AcctABC{
private:
char *label;
double price;
public:
AcctABC();
AcctABC(const char *l,double p);
AcctABC(const AcctABC& abc);
virtual ~AcctABC(){delete[] label;}
virtual void View()const=0;
AcctABC& operator=(const AcctABC& abc);
};
//*********************抽象基类AcctABC的实现*********************
AcctABC::AcctABC(){
label=nullptr;
price=0;
}
AcctABC::AcctABC(const char *l,double p){
label=new char[strlen(l)+1];
strcpy(label,l);
price=p;
}
AcctABC::AcctABC(const AcctABC& abc){
label=new char[strlen(abc.label)+1];
strcpy(label,abc.label);
price=abc.price;
}
AcctABC& AcctABC::operator=(const AcctABC& abc){
if(this==&abc) return *this;
delete[] label;
label=new char[strlen(abc.label)+1];
strcpy(label,abc.label);
price=abc.price;
return *this;
}
void AcctABC::View()const{
cout<<"Label: "<<label<<std::endl;
cout<<"Price: "<<price<<std::endl;
}
//第一个派生类
//*********************派生类baseDMA的声明*********************
class baseDMA:public AcctABC{
private:
int rating;
public:
baseDMA(const char* l="null",double p=0.0,int r=0);
baseDMA(const baseDMA &rs);
virtual ~baseDMA(){};
virtual void View()const;
baseDMA& operator=(const baseDMA &rs);
};
//*********************派生类baseDMA的实现*********************
baseDMA::baseDMA(const char* l,double p,int r):AcctABC(l,p){
rating=r;
}
baseDMA::baseDMA(const baseDMA &rs):AcctABC(rs){
rating=rs.rating;
}
void baseDMA::View()const{ //cosnt函数中不能调用非const函数,所以getLable()需要是const
AcctABC::View();
cout<<"Rating: "<<rating<<std::endl;
}
baseDMA& baseDMA::operator=(const baseDMA &rs){
if(this==&rs) return *this;
AcctABC::operator=(rs);
rating=rs.rating;
return *this;
}
//*********************派生类lacksDMA的声明*********************
//无动态内存分配
class lacksDMA:public AcctABC{
private:
enum{COL_LEN=40};
char color[COL_LEN];
public:
lacksDMA(const char* c="black",const char* l="null",double p=0.0);
lacksDMA(const lacksDMA& ls);
virtual ~lacksDMA(){}
virtual void View()const;
lacksDMA& operator=(const lacksDMA& ls);
};
//*********************派生类lackDMA的实现*********************
lacksDMA::lacksDMA(const char* c,const char* l,double p):AcctABC(l,p){
std::strncpy(color,c,39);
color[39]='\0';
}
lacksDMA::lacksDMA(const lacksDMA& ls):AcctABC(ls){
std::strncpy(color,ls.color,COL_LEN-1);
color[COL_LEN-1]='\0';
}
lacksDMA& lacksDMA::operator=(const lacksDMA& ls){
if(this==&ls) return *this;
AcctABC::operator=(ls);
std::strncpy(color,ls.color,COL_LEN-1);
color[COL_LEN-1]='\0';
return *this;
}
void lacksDMA::View()const{
AcctABC::View();
cout<<"Color: "<<color<<std::endl;
}
//*********************派生类hasDMA的声明*********************
//有动态内存分配
class hasDMA:public AcctABC{
private:
char* style;
public:
hasDMA(const char* s="none",const char* l="null",double p=0.0);
hasDMA(const hasDMA&hs);
virtual ~hasDMA();
hasDMA& operator=(const hasDMA &hs);
virtual void View()const;
};
//*********************派生类hasDMA的实现*********************
hasDMA::hasDMA(const char* s,const char* l,double p):AcctABC(l,p){
style=new char[std::strlen(s)+1];
std::strcpy(style,s);
}
hasDMA::hasDMA(const hasDMA& hs):AcctABC(hs){
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;
AcctABC::operator=(hs);
delete[] style;
style=new char[std::strlen(hs.style)+1];
std::strcpy(style,hs.style);
return *this;
}
void hasDMA::View()const{
AcctABC::View();
cout<<"Style: "<<style<<std::endl;
}
//*********************测试函数main*********************
const int CNT=5;
int main(){
AcctABC* pobject[CNT];
string temp;
double price;
char type;
for(int i=0;i<CNT;i++){
cout<<"Enter the lable: ";
getline(cin,temp);
cout<<"Enter the price: ";
cin>>price;
cout<<"Enter 1 for baseDMA, 2 for lacksDMA, or 3 for hasDMA: ";
while(cin>>type&&(type!='1'&&type!='2'&&type!='3'))
cout<<"Enter either 1, 2, or 3 : ";
while(cin.get()!='\n')
continue;
switch(type){
case '1': { int rating;
cout<<"Enter the rating: ";
cin>>rating; cin.get();
pobject[i]=new baseDMA(temp.c_str(),price,rating); }
break;
case '2': { string color;
cout<<"Enter the color: ";
getline(cin,color);
pobject[i]=new lacksDMA(color.c_str(),temp.c_str(),price); }
break;
case '3': { string style;
cout<<"Enter the style: ";
getline(cin,style);
pobject[i]=new hasDMA(style.c_str(),temp.c_str(),price); }
break;
}
}
cout<<endl;
for(int i=0;i<CNT;i++){
pobject[i]->View();
cout<<endl;
}
for(int i=0;i<CNT;i++)
delete pobject[i];
return 0;
}
4
题目
Benevoletn Order of Programmers用来维护瓶装葡萄酒。为描述它,BOP Portmaster设置一个Port类,其声明如下:
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);
};
show()方法按照下面的格式显示信息(末尾没有换行符):
Brand: Gallo
Kind: tawny
Bottles: 20
operator<<()函数按照下面的格式显示信息(末尾没有换行符):
Gallo, tawny, 20
PortMaster完成了Port类的方法定义后派生了VintagePort类,然后被解职——因为不小心将一瓶45度的Cockburn泼到了正在准备烤肉调料的人身上,VintagePort类如下所示:
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);
virtual void Show()const;
friend ostream& operator<<(ostream& os,const VintagePort &vp);
};
您被指定负责完成VintagePort。
a.第一个任务是重建Port方法定义,因为前任被开除时销毁了方法定义。
b.第二个任务是解释为什么有的方法重新定义了,而有些方法没有重新定义。
c.第三个任务是解释为何没有将operator=()和operator<<()声明为虚的。
d.第四个任务是提供VintagePort中各个方法的定义。
题解
#include<iostream>
#include<cstring>
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);
};
//******************基类的实现******************
Port::Port(const char* br, const char *st,int b){
brand=new char[strlen(br)+1];
strcpy(brand,br);
strncpy(style,st,19); 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,19); 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,19); style[19]='\0';
bottles=p.bottles;
return *this;
}
Port& Port::operator+=(int b){
bottles+=b;
}
Port& Port::operator-=(int b){
if(b>bottles) bottles=0; //如果超出可减范围,则直接置零
else 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;
}
//******************派生类的声明******************
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);
virtual void Show()const;
friend ostream& operator<<(ostream& os,const VintagePort &vp);
};
//c
//(1)
//重载的赋值运算符不能被继承,因为重载的赋值运算符一般为自身类型赋值为自身类型,
//基类的赋值运算符重载参数为基类的引用,返回值也为基类引用,派生类使用时,无法将基类自动转化为派生类。
//(2)
//operator<<函数是友元函数,不是成员函数,无法继承
//******************派生类的实现******************
VintagePort::VintagePort(){
nickname=nullptr;
year=0;
}
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(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;
}
Comments | NOTHING