1.以下面的类声明为基础:
// base class
class Cd { //represents a CD disk
private:
char performers[50];
char label[20];
int selections; //number of selections
double playtime; //playing time in minute
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中主要作品的字符串。修改上述声明,使基类的搜有函数都是虚的。如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:
#include
using namespace std;
#include"classic.h" //which will contain #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(); //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: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd& disk)
{
disk.Report();
}
答:
//classic.h
class Cd { //represents a CD disk
private:
char performers[50]; //表演者
char label[20]; //标签
int selections; //选择次数
double playtime; //播放时间
public:
Cd(char * s1, char * s2, int n, double x); //构造函数
Cd() { }
virtual ~Cd() {} //析构函数
virtual void Report() const; //报告所有数据
virtual Cd & operator=(const Cd & d); //赋值运算符
};
//派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。
//修改上述声明,使基类的搜有函数都是虚的。
//如果上述定义声明的某个方法并不需要,则请删除它。
class Classic :public Cd //派生类
{
private:
char productions[50]; //主要作品
public:
Classic() {}
Classic(const char*pr, char*s1, char *s2, int n, double x); //构造函数
virtual void Report()const;
virtual Classic & operator=(const Classic & d); //赋值运算符
};
//classic.cpp
#include
#include"classic.h"
using std::cout;
using std::endl;
//Cd类
Cd::Cd(char * s1, char * s2, int n, double x) //构造函数
{
strcpy_s(performers, strlen(s1) + 1, s1);
strcpy_s(label, strlen(s2) + 1, s2);
selections = n;
playtime = x;
}
void Cd::Report() const //报告所有数据
{
cout << "表演者:" << performers << endl;
cout << "标 签:" << label << endl;
cout << "选 择:" << selections << endl;
cout << "总时长:" << playtime << "分钟" << endl;
}
Cd & Cd::operator=(const Cd & d) //赋值运算符
{
if (this == &d)return *this;
strcpy_s(performers, strlen(d.performers) + 1, d.performers);
strcpy_s(label, strlen(d.label) + 1, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
//Classic类
Classic::Classic(const char*pr, char*s1, char *s2, int n, double x) :Cd(s1, s2, n, x) //构造函数
{
strcpy_s(productions, strlen(pr) + 1, pr);
}
void Classic::Report()const
{
Cd::Report();
cout << "主要作品:" << productions << endl;
}
Classic & Classic::operator=(const Classic & d) //赋值运算符
{
if (this == &d)return *this;
Cd::operator=(d);
strcpy_s(productions, strlen(d.productions) + 1, d.productions);
return *this;
}
//1.cpp main函数测试用
#include
using namespace std;
#include"classic.h" //which will contain #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(); //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: ";
Classic copy;
copy = c2;
copy.Report();
system("pause");
return 0;
}
void Bravo(const Cd& disk)
{
disk.Report();
}
2.完成练习1,但让两个类使用动态内存分配而不是长度固定的数组来记录字符串。
答:修改如下(只包含头文件和classic.cpp源代码文件)
//classic.h
class Cd { //represents a CD disk
private:
char *performers; //表演者
char *label; //标签
int selections; //选择次数
double playtime; //播放时间
public:
Cd(char * s1, char * s2, int n, double x); //构造函数
Cd() { delete[]performers;delete[]label; }
virtual ~Cd() {} //析构函数
virtual void Report() const; //报告所有数据
virtual Cd & operator=(const Cd & d); //赋值运算符
};
//派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。
//修改上述声明,使基类的搜有函数都是虚的。
//如果上述定义声明的某个方法并不需要,则请删除它。
class Classic :public Cd //派生类
{
private:
char *productions; //主要作品
public:
Classic() { delete[]productions; }
Classic(const char*pr, char*s1, char *s2, int n, double x); //构造函数
virtual void Report()const;
virtual Classic & operator=(const Classic & d); //赋值运算符
};
//classic.cpp
#include
#include"classic.h"
using std::cout;
using std::endl;
//Cd类
Cd::Cd(char * s1, char * s2, int n, double x) //构造函数
{
performers = new char[strlen(s1) + 1];
strcpy_s(performers, strlen(s1) + 1, s1);
label = new char[strlen(s1) + 1];
strcpy_s(label, strlen(s2) + 1, s2);
selections = n;
playtime = x;
}
void Cd::Report() const //报告所有数据
{
cout << "表演者:" << performers << endl;
cout << "标 签:" << label << endl;
cout << "选 择:" << selections << endl;
cout << "总时长:" << playtime << "分钟" << endl;
}
Cd & Cd::operator=(const Cd & d) //赋值运算符
{
if (this == &d)return *this;
delete[]performers;
performers = new char[strlen(d.performers) + 1];
strcpy_s(performers, strlen(d.performers) + 1, d.performers);
delete[]label;
label = new char[strlen(d.label) + 1];
strcpy_s(label, strlen(d.label) + 1, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
//Classic类
Classic::Classic(const char*pr, char*s1, char *s2, int n, double x) :Cd(s1, s2, n, x) //构造函数
{
productions = new char[strlen(pr) + 1];
strcpy_s(productions, strlen(pr) + 1, pr);
}
void Classic::Report()const
{
Cd::Report();
cout << "主要作品:" << productions << endl;
}
Classic & Classic::operator=(const Classic & d) //赋值运算符
{
if (this == &d)return *this;
Cd::operator=(d);
delete[]productions;
productions = new char[strlen(d.productions) + 1];
strcpy_s(productions, strlen(d.productions) + 1, d.productions);
return *this;
}
3.修改baseDMA-lacksDMA-hasDMA类层次,让三个类都从一个ABC派生而来,然后使用与程序清单13.10相似的程序对结果进行测试。也就是说,它应使用ABC指针数组,并让用户决定要创建的对象类型。在类定义中添加virtual View()方法以处理数据显示。
//DMA.h
//ABC
class DMA
{
private:
char *label;
int rating;
public:
DMA(const char*l = "null", int r = 0);
DMA(const DMA& dm);
virtual ~DMA() { delete[]label; }
virtual void view() = 0;
DMA & operator=(const DMA&dm);
};
class baseDMA :public DMA
{
public:
baseDMA(const char*l = "null", int r = 0) :DMA(l, r) {};
~baseDMA() {};
virtual void view();
};
class lackDMA :public DMA
{
private:
char color[40];
public:
lackDMA(const char*l = "null", int r = 0, char* m = "yellow") :DMA(l, r)
{
strcpy_s(color, strlen(m) + 1, m);
}
~lackDMA() {}
virtual void view();
};
class hasDMA:public DMA
{
private:
char * style;
public:
hasDMA(const char*l = "null", int r = 0, const char*m="null");
hasDMA(const DMA&dm, const char*m);
hasDMA(const hasDMA& ha);
virtual const hasDMA& operator=(const hasDMA& ha);
~hasDMA() { delete[] style; }
virtual void view();
};
//DMA.cpp
#include
#include"DMA.h"
using std::cout;
using std::endl;
//ABC
DMA::DMA(const char*l, int r)
{
label = new char[strlen(l) + 1];
strcpy_s(label, strlen(l) + 1, l);
rating = r;
}
DMA::DMA(const DMA& dm)
{
label = new char[strlen(dm.label) + 1];
strcpy_s(label, strlen(dm.label) + 1, dm.label);
rating = dm.rating;
}
DMA & DMA::operator=(const DMA&dm)
{
if (this == &dm)return *this;
delete[]label;
label = new char[strlen(dm.label) + 1];
strcpy_s(label, strlen(dm.label) + 1, dm.label);
rating = dm.rating;
return *this;
}
void DMA::view()
{
cout << "**********" << endl;
cout << "label:" << label << endl;
}
//baseDMA
void baseDMA::view()
{
DMA::view();
}
//lackDMA
void lackDMA::view()
{
DMA::view();
cout << "color:" << color << endl;
}
//hasDMA
hasDMA::hasDMA(const char*l, int r, const char*m) :DMA(l, r)
{
style = new char[strlen(m) + 1];
strcpy_s(style, strlen(m) + 1, m);
}
hasDMA::hasDMA(const DMA&dm, const char*m) :DMA(dm)
{
style = new char[strlen(m) + 1];
strcpy_s(style, strlen(m) + 1, m);
}
hasDMA::hasDMA(const hasDMA& ha) :DMA(ha)
{
style = new char[strlen(ha.style) + 1];
strcpy_s(style, strlen(ha.style) + 1, ha.style);
}
const hasDMA& hasDMA::operator=(const hasDMA& ha)
{
if (this == &ha)return *this;
DMA::operator=(ha);
delete[]style;
style = new char[strlen(ha.style) + 1];
strcpy_s(style, strlen(ha.style) + 1, ha.style);
return *this;
}
void hasDMA::view()
{
DMA::view();
cout << "style:" << style << endl;
}
//1.cpp main函数测试用
#include
#include"DMA.h"
using namespace std;
int main()
{
DMA* one[3]; //ABC类指针
for (int i = 0;i < 3;i++)
{
cout << "请输入你的选择:\n1.使用baseDMA类\t2.使用lackDMA类\t3.使用hasDMA类" << endl;
cout << "选择->";
int choice;
cin >> choice;
cin.sync();
cin.clear();
char *label = new char[30];
cout << "请输入标签:";
cin >> label;
cout << "请输入等级:";
int rating;
cin >> rating;
char *color = new char[30];
char *style = new char[30];
if (choice == 2)
{
cout << "请输入颜色:";
cin >> color;
}
else if (choice == 3)
{
cout << "请输入风格:";
cin >> style;
}
if (choice == 1)
one[i] = new baseDMA(label, rating);
else if (choice == 2)
one[i] = new lackDMA(label, rating, color);
else if (choice == 3)
one[i] = new hasDMA(label, rating, style);
} //输入for结束
for (int i = 0;i < 3;i++) //显示
one[i]->view();
system("pause");
return 0;
}
显示:
请输入你的选择:
1.使用baseDMA类 2.使用lackDMA类 3.使用hasDMA类
选择->1
请输入标签:A
请输入等级:10
请输入你的选择:
1.使用baseDMA类 2.使用lackDMA类 3.使用hasDMA类
选择->2
请输入标签:B
请输入等级:15
请输入颜色:
白
请输入你的选择:
1.使用baseDMA类 2.使用lackDMA类 3.使用hasDMA类
选择->3
请输入标签:C
请输入等级:20
请输入风格:清爽
**********
label:A
**********
label:B
color:白
**********
label:C
style:清爽
请按任意键继续. . .
4.Benevolent Order of Programmers用来维护瓶装葡萄酒箱。为描述它,BOP Portmaster设置了一个Port类,并声明如下:
#include
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); //add 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, const char *st, int b, const char * nn, int y);
//注:我认为上面这个构造函数少了一个st字符串,这个字符串是用于给style字符串赋值的
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
#include
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); //cpoy constructor
virtual ~Port() { delete[] brand; }
Port & operator=(const Port&p);
Port & operator+=(int b); //add 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
#include"port.h"
using namespace std;
//Port类
Port::Port(const char * br, const char *st, int b)
{
brand = new char[strlen(br) + 1];
strcpy_s(brand, strlen(br) + 1, br);
strcpy_s(style, strlen(st) + 1, st);
bottles = b;
}
Port::Port(const Port & p) //copy constructor
{
brand = new char[strlen(p.brand) + 1];
strcpy_s(brand, strlen(p.brand) + 1, p.brand);
strcpy_s(style, strlen(p.style) + 1, 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_s(brand, strlen(p.brand) + 1, p.brand);
strcpy_s(style, strlen(p.style) + 1, p.style);
bottles = p.bottles;
return *this;
}
Port & Port::operator+=(int b) //add b to bottles
{
bottles += b;
return *this;
}
Port & Port::operator-=(int b) //subtracts b from bottles , if available
{
bottles -= b;
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;
}
//VintagePort类
VintagePort::VintagePort() :Port()
{
}
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_s(nickname, strlen(nn) + 1, nn);
year = y;
}
VintagePort::VintagePort(const VintagePort & vp) :Port(vp)
{
nickname = new char[strlen(vp.nickname) + 1];
strcpy_s(nickname, strlen(vp.nickname) + 1, 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_s(nickname, strlen(vp.nickname) + 1, 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 << ", " << vp.nickname << ", " << vp.year;
return os;
}