- 根据声明编写派生类classic,添加char成员(存储CD中主要作品的字符串),并修改声明使得基类成员函数为虚,并且如果某个方法不需要,删除掉。
题目类声明
class Cd{
private:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(char *s1,char *s2,int n,double x);
Cd(const Cd&c);
Cd();
~Cd();
void report()const;
Cd &operator=(const Cd&c);
};
题目要求的测试程序
#include <iostream>
#include "cd.h"
using namespace std;
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:" << endl;
c1.report();
c2.report();
cout << endl;
cout << "Using type cd * pointer to objects:" << endl;
pcd->report();
pcd = &c2;
pcd->report();
cout << endl;
cout << "Calling a function with a Cd reference argument:" << endl;
Bravo(c1);
Bravo(c2);
cout << endl;
cout << "Testing assignment:" << endl;
classic copy;
copy = c2;
copy.report();
system("pause");
return 0;
}
void Bravo(const Cd &disk) { disk.report(); }
完善后的类声明
//base class
class Cd
{
private:
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(const char *s1 = "nobody", const char *s2 = "null", int n = 0, double x = 0.0);
Cd(const Cd &c); //copy constructor
virtual ~Cd() {}
virtual void report() const;
virtual Cd &operator=(const Cd &c);
};
//derived class
class classic : public Cd
{
private:
char work[20];
public:
classic(const char *s1 = "nobody", const char *s2 = "null", const char *c = "null", int s = 0, double p = 0.0);
classic(const Cd &c, const char *w);
virtual void report() const;
virtual classic &operator=(const classic &c);
};
方法实现
#include <iostream>
#include "cd.h"
#include <cstring>
//Cd methods
Cd::Cd(const char *s1, const char *s2, int n, double x)
{
strcpy(performers, s1);
strcpy(label, s2);
selections = n;
playtime = x;
}
Cd::Cd(const Cd &c)
{
strcpy(performers, c.performers);
strcpy(label, c.label);
selections = c.selections;
playtime = c.playtime;
} //copy constructor
void Cd::report() const
{
std::cout << "Performers: " << performers << "\n";
std::cout << "label: " << label << " number of selections:" << selections << std::endl;
std::cout << "playing time in minutes: " << playtime << std::endl;
}
Cd &Cd::operator=(const Cd &c)
{
if (this == &c)
return *this;
strcpy(performers, c.performers);
strcpy(label, c.label);
selections = c.selections;
playtime = c.playtime;
return *this;
}
//classic methods
classic::classic(const char *s1, const char *s2, const char *c, int s, double p) : Cd(s1, s2, s, p)
{
strcpy(work, c);
}
classic::classic(const Cd &c, const char *w) : Cd(c)
{
strcpy(work, w);
}
void classic::report() const
{
Cd::report();
std::cout << "Main work in CD: " << work << std::endl;
}
classic &classic::operator=(const classic &c)
{
if (this == &c)
return *this;
Cd::operator=(c);
strcpy(work, c.work);
return *this;
}
- 在练习一的基础上进行改动,让两个类以动态内存分配来记录字符串。由于派生类和基类都使用new来动态分配内存,则派生类的析构函数、复制构造函数和赋值运算符函数就不能使用默认函数了,应该重新声明定义。
类声明
//base class
class Cd
{
private:
char *performers;
char *label;
int selections;
double playtime;
public:
Cd(const char *s1 = "nobody", const char *s2 = "null", int n = 0, double x = 0.0);
Cd(const Cd &c); //copy constructor
virtual ~Cd();
virtual void report() const;
virtual Cd &operator=(const Cd &c);
};
//derived class
class classic : public Cd
{
private:
char *work;
public:
classic(const char *s1 = "nobody", const char *s2 = "null", const char *c = "null", int s = 0, double p = 0.0);
classic(const Cd &c, const char *w);
classic(const classic &c);
~classic();
virtual void report() const;
virtual classic &operator=(const classic &c);
};
方法实现声明
#include <iostream>
#include "cd.h"
#include <cstring>
//Cd methods
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 &c)
{
performers = new char[strlen(c.performers) + 1];
label = new char[strlen(c.label) + 1];
strcpy(performers, c.performers);
strcpy(label, c.label);
selections = c.selections;
playtime = c.playtime;
} //copy constructor
Cd::~Cd()
{
delete[] performers;
delete[] label;
}
void Cd::report() const
{
std::cout << "Performers: " << performers << "\n";
std::cout << "label: " << label << "\nnumber of selections:" << selections << std::endl;
std::cout << "playing time in minutes: " << playtime << std::endl;
}
Cd &Cd::operator=(const Cd &c)
{
if (this == &c)
return *this;
delete[] performers;
performers = new char[strlen(c.performers) + 1];
delete[] label;
label = new char[strlen(c.label) + 1];
strcpy(performers, c.performers);
strcpy(label, c.label);
selections = c.selections;
playtime = c.playtime;
return *this;
}
//classic methods
classic::classic(const char *s1, const char *s2, const char *c, int s, double p) : Cd(s1, s2, s, p)
{
work = new char[strlen(c) + 1];
strcpy(work, c);
}
classic::classic(const Cd &c, const char *w) : Cd(c)
{
work = new char[strlen(w) + 1];
strcpy(work, w);
}
classic::classic(const classic &c) : Cd(c)
{
work = new char[strlen(c.work) + 1];
strcpy(work, c.work);
}
classic::~classic()
{
delete[] work;
}
void classic::report() const
{
Cd::report();
std::cout << "Main work in CD: " << work << std::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;
}
一样的测试程序,一样的测试结果,为了验证,还是展示一下吧
- 修改抽象基类例子中的三个类,使其从一个ABC派生出来,并使用书本的测试程序进行测试。
类声明头文件
#include <iostream>
//base ABC class
class ABC
{
public:
ABC() {}
virtual ~ABC() {}
virtual void view() const = 0;
};
//derived class baseDMA
class baseDMA : public ABC
{
private:
char *label;
int rating;
public:
baseDMA(const char *l = "null", int r = 0);
baseDMA(const baseDMA &bs);
~baseDMA();
baseDMA &operator=(const baseDMA &bs);
friend std::ostream &operator<<(std::ostream &os, const baseDMA &bs);
virtual void view() const;
};
//derived class lacksDMA
class lacksDMA : public baseDMA
{
private:
enum
{
COL_LEN = 40
};
char color[COL_LEN];
public:
lacksDMA(const baseDMA &bs, const char *c);
lacksDMA(const char *c = "blank", const char *l = "null", int r = 0);
friend std::ostream &operator<<(std::ostream &os, const lacksDMA &ls);
virtual void view() const;
};
//derived class hasDMA
class hasDMA : public baseDMA
{
private:
char *style;
public:
hasDMA(const char *s = "none", const char *l = "null", int r = 0);
hasDMA(const char *s, const baseDMA &bs);
hasDMA(const hasDMA &hs);
~hasDMA();
hasDMA &operator=(const hasDMA &hs);
friend std::ostream &operator<<(std::ostream &os, const hasDMA &hs);
virtual void view() const;
};
方法实现
#include "ABC.h"
#include <cstring>
//baseDMa methods
baseDMA::baseDMA(const char *l, int r)
{
label = new char[strlen(l) + 1];
strcpy(label, l);
rating = r;
}
baseDMA::baseDMA(const baseDMA &bs)
{
delete[] label;
label = new char[strlen(bs.label) + 1];
strcpy(label, bs.label);
rating = bs.rating;
}
baseDMA::~baseDMA()
{
delete[] label;
}
baseDMA &baseDMA::operator=(const baseDMA &bs)
{
if (this == &bs)
return *this;
delete[] label;
label = new char[strlen(bs.label) + 1];
strcpy(label, bs.label);
rating = bs.rating;
return *this;
}
std::ostream &operator<<(std::ostream &os, const baseDMA &bs)
{
os << "Label: " << bs.label << " rating: " << bs.rating;
return os;
}
void baseDMA::view() const
{
std::cout << "Label: " << label << " rating: " << rating;
}
//lacksDMA methods
lacksDMA::lacksDMA(const baseDMA &bs, const char *c) : baseDMA(bs)
{
strcpy(color, c);
}
lacksDMA::lacksDMA(const char *c, const char *l, int r) : baseDMA(l, r)
{
strcpy(color, l);
}
std::ostream &operator<<(std::ostream &os, const lacksDMA &ls)
{
os << "color: " << ls.color;
return os;
}
void lacksDMA::view() const
{
baseDMA::view();
std::cout << "color: " << color << std::endl;
}
//hasDMA methods
hasDMA::hasDMA(const char *s, const char *l, int r) : baseDMA(l, r)
{
style = new char[strlen(s) + 1];
strcpy(style, s);
}
hasDMA::hasDMA(const char *s, const baseDMA &bs) : baseDMA(bs)
{
style = new char[strlen(s) + 1];
strcpy(style, s);
}
hasDMA::hasDMA(const hasDMA &hs)
{
delete[] style;
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;
delete[] style;
style = new char[strlen(hs.style) + 1];
strcpy(style, hs.style);
}
std::ostream &operator<<(std::ostream &os, const hasDMA &hs)
{
os << "style: " << hs.style;
return os;
}
void hasDMA::view() const
{
baseDMA::view();
std::cout << "style: " << style << std::endl;
}
测试程序
#include <iostream>
#include <string>
#include "ABC.h"
using namespace std;
const int CLIENTS = 4;
const int Max = 20;
int main()
{
using std::cin;
using std::cout;
using std::endl;
ABC *p[CLIENTS];
string temp;
int tempnum;
string stemp;
string ctemp;
char kind;
for (int i = 0; i < CLIENTS; i++)
{
cout << "Enter the label: ";
getline(cin, temp);
cout << "Enter the rating: ";
cin >> tempnum;
cout << "Enter 1 for baseDMA or "
<< "2 for lacksDMA "
<< "3 for hasDMA:";
while (cin >> kind && (kind != '1' && kind != '2' && kind != '3'))
cout << "Enter either 1 or 2: ";
while (cin.get() != '\n')
continue;
if (kind == '1')
p[i] = new baseDMA(temp.c_str(), tempnum);
else if (kind == '2')
{
cout << "Enter the color: ";
getline(cin, ctemp);
p[i] = new lacksDMA(ctemp.c_str(), temp.c_str(), tempnum);
}
else
{
cout << "Enter the style: ";
getline(cin, stemp);
p[i] = new hasDMA(stemp.c_str(), temp.c_str(), tempnum);
}
}
cout << endl;
for (int j = 0; j < CLIENTS; j++)
p[j]->view();
for (int k = 0; k < CLIENTS; k++)
delete p[k];
system("pause");
return 0;
}
总结:能用string就用string,程序能运行但卡住就一定是换行符卡在了输入流里。结果就不显示了,阿婆主心力交瘁了。
4. 完善port类和vintageport类
#include <iostream>
using namespace std;
//base class
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); //add b to bottles
Port &operator-=(int b); //subtracts b from bottles
int bottlecount() const { return bottles; }
virtual void show() const;
friend ostream &operator<<(ostream &os, const Port &p);
};
//derived class
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);
};
方法实现文件
#include "bop.h"
#include <cstring>
//Port methods
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)
{
delete[] brand;
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;
return *this;
}
Port &Port::operator+=(int b)
{
bottles += b;
return *this;
} //add b to bottles
Port &Port::operator-=(int b)
{
if (bottles >= b)
bottles -= b;
return *this;
} //subtracts b from bottles
void Port::show() const
{
std::cout << "Brand: " << brand << std::endl;
std::cout << "Kind: " << style << std::endl;
std::cout << "Bottles: " << bottles << std::endl;
}
ostream &operator<<(ostream &os, const Port &p)
{
os << p.brand << "," << p.style << ", " << p.bottles;
return os;
}
//VintagePort methods
VintagePort::VintagePort()
{
strcpy(nickname, "vintage");
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)
{
delete[] nickname;
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;
delete[] nickname;
nickname = new char[strlen(vp.nickname) + 1];
strcpy(nickname, vp.nickname);
year = vp.year;
return *this;
}
void VintagePort::show() const
{
Port::show();
std::cout << "Nickname: " << nickname << std::endl;
std::cout << "Year: " << year << std::endl;
}
ostream &operator<<(ostream &os, const VintagePort &vp)
{
os << Port(vp);
os << " ," << vp.nickname << ", " << vp.year;
return os;
}
测试程序
#include <iostream>
#include "bop.h"
using namespace std;
int main()
{
{
Port port1("Gallo", "tawny", 20);
VintagePort vp("ooooo", 20, "The Noble", 1997);
port1.show();
vp.show();
cout << endl;
VintagePort vp2 = vp;
Port port2 = port1;
cout << vp2 << endl;
cout << port2 << endl;
system("pause");
return 0;
}
}
观察测试程序可以看到,我在主运行外面又加了一个大括号,具体原因我也没明白过来,不过可以猜想是析构函数的锅,看过c++ primer plus的都知道,在讲解析构函数的章节中有过这种做法的出现就是程序清单10.6,要确认我的想法就是在析构函数中加上一些启示语句,然后删减大括号进行对比测试即可,这里我就不测试了,大家如果有不同意见,欢迎交流。