1.
首先,對於將題中基類修改爲虛函數版本,我們只需要將基類的公有函數部分除構造函數和友元之外的函數,聲明時前面加上關鍵字virtual即可;然後對於派生類,我們在私有成員裏面添加一個char數組,然後將繼承的函數寫出來即可。
cd.h
#ifndef CD_H
#define CD_H
#include <iostream>
using namespace std;
class Cd{
char performers[50];
char label[20];
int selections;
double playtime;
public:
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
virtual ~Cd();
virtual void Report() const ;
virtual Cd &operator=(const Cd & d);
};
class Classic : public Cd
{
char mainworks[50];//添加一組char成員,用於存儲指出CD中主要作品的字符串
public:
Classic(char * s0, char * s1, char * s2, int n, double x);
Classic(char * s0, Cd & rs);
Classic();
virtual ~Classic();
virtual void Report() const ;
virtual Classic &operator=(const Classic & d);
};
#endif
cd.cpp
#include "cd.h"
#include <iostream>
using namespace std;
#include <cstring>
Cd::Cd(char *s1, char *s2, int n, double x)
{
strcpy_s(performers, 50, s1);
strcpy_s(label, 20, s2);
selections = n;
playtime = x;
}
Cd::Cd()
{
strcpy_s(performers, 50, "null");
strcpy_s(label, 20, "null");
selections = 0;
playtime = 0;
}
Cd::~Cd()
{}
void Cd ::Report() const
{
cout << "In this CD disk, the performrs are " << performers << endl;
cout << "The labels are " << label << endl;
cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}
Cd & Cd::operator=(const Cd & d)
{
strcpy_s(performers, 50, d.performers);
strcpy_s(label, 20, d.label);
selections = d.selections;
playtime = d.playtime;
return *this;
}
Classic::Classic(char *s0, char *s1, char *s2, int n, double x)
: Cd(s1, s2, n, x)
{
strcpy_s(mainworks, 50, s0);
}
Classic::Classic(char *s0, Cd &rs)
: Cd(rs)
{
strcpy_s(mainworks, 50, s0);
}
Classic::Classic()
: Cd()
{
strcpy_s(mainworks, 50, "null");
}
Classic::~Classic()
{}
void Classic::Report() const
{
Cd::Report();
cout << "The main works of this disk are " << mainworks << endl;
}
Classic & Classic::operator=(const Classic & d)
{
if(this == &d)
return *this;
Cd::operator=(d);
strcpy_s(mainworks, 50, d.mainworks);
return *this;
}
play.cpp
//檢測文件按題目即可
#include <iostream>
using namespace std;
#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();
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: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd & disk)
{
disk.Report();
}
2.
練習1中,我們的成員變量的類型是使用的char數組,本題要求我們改爲動態內存分配,所以成員變量的類型我們可以選爲char指針,那麼這裏最最需要注意的就是,這樣改過之後,析構函數就必須要發揮作用了,析構函數內部就必須要把構造函數裏面初始化時動態分配的內存給delete掉。
cd.h
#ifndef CD_H
#define CD_H
#include <iostream>
using namespace std;
class Cd{
char * performers;
char * label;
int selections;
double playtime;
public:
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
virtual ~Cd();
virtual void Report() const ;
virtual Cd &operator=(const Cd & d);
};
class Classic : public Cd
{
char * mainworks;//添加一組char成員,用於存儲指出CD中主要作品的字符串
public:
Classic(char * s0, char * s1, char * s2, int n, double x);
Classic(char * s0, Cd & rs);
Classic();
virtual ~Classic();
virtual void Report() const ;
virtual Classic &operator=(const Classic & d);
};
#endif
接下來對於實現文件呢,一方面注意構造函數內部初始化時,都必須首先進行動態內存分配,然後纔可以進行strcpy_s函數的賦值,另一方面就是析構函數必須把構造函數裏面動態分配的內存都刪掉。其他內容不需要改變。
cd.cpp
#include "cd.h"
#include <iostream>
using namespace std;
#include <cstring>
Cd::Cd(char *s1, char *s2, int n, double x)
{
performers = new char [strlen(s1) + 1];//注意構造函數內部初始化時,都必須首先進行動態內存分配,然後纔可以進行strcpy_s函數的賦值
strcpy_s(performers, strlen(s1) + 1, s1);
label = new char [strlen(s2) + 1];
strcpy_s(label, strlen(s2) + 1, s2);
selections = n;
playtime = x;
}
Cd::Cd()
{
performers = new char [5];
strcpy_s(performers, 5, "null");
label = new char [5];
strcpy_s(label, 5, "null");
selections = 0;
playtime = 0;
}
Cd::~Cd()
{
delete [] performers;//析構函數必須把構造函數裏面動態分配的內存都刪掉
delete [] label;
}
void Cd ::Report() const
{
cout << "In this CD disk, the performrs are " << performers << endl;
cout << "The labels are " << label << endl;
cout << "There are " << selections << " selections and lasts " << playtime << " minutes.\n";
}
Cd & Cd::operator=(const Cd & d)
{
performers = new char [strlen(d.performers) + 1];
strcpy_s(performers, strlen(d.performers) + 1, d.performers);
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(char *s0, char *s1, char *s2, int n, double x)
: Cd(s1, s2, n, x)
{
mainworks = new char [strlen(s0) + 1];
strcpy_s(mainworks, strlen(s0) + 1, s0);
}
Classic::Classic(char *s0, Cd &rs)
: Cd(rs)
{
mainworks = new char [strlen(s0) + 1];
strcpy_s(mainworks, strlen(s0) + 1, s0);
}
Classic::Classic()
: Cd()
{
mainworks = new char [5];
strcpy_s(mainworks, 5, "null");
}
Classic::~Classic()
{
delete [] mainworks;
}
void Classic::Report() const
{
Cd::Report();
cout << "The main works of this disk are " << mainworks << endl;
}
Classic & Classic::operator=(const Classic & d)
{
if(this == &d)
return *this;
Cd::operator=(d);
mainworks = new char [strlen(d.mainworks) + 1];
strcpy_s(mainworks, strlen(d.mainworks) + 1, d.mainworks);
return *this;
}
檢測文件不變,同上題。
3.
本題要求在DMA類的基礎上進行修改,將三個類統一改爲從一個基類ABC派生而來。這裏要求使用ABC類指針數組並讓用戶決定創建的對象類型,即需要做一個交互;同時添加一個View方法用於數據顯示,並要求該方法爲虛函數。本來lacksDMA類和hasDMA類就是派生於baseDMA類的,所以我們只需使baseDMA類派生於ABC類即可,另外在每個類內部添加一個View方法。
dma.h
#ifndef DMA_H
#define DMA_H
#include <iostream>
using namespace std;
class ABC{
public:
ABC();
~ABC();
virtual void View() = 0;//題要求在類定義中添加virtual View()方法以處理數據顯示
};
class baseDMA : public ABC
{
char * label;
int rating;
public:
baseDMA(const char * l = "null", int r = 0);
baseDMA(const baseDMA & rs);
virtual ~baseDMA();
baseDMA &operator=(const baseDMA & rs);
friend ostream &operator<< (ostream & os, const baseDMA & rs);
virtual void View();
};
class lacksDMA : public baseDMA
{
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);
friend ostream &operator<<(ostream & os, const lacksDMA & rs);
virtual void View();
};
class hasDMA : public baseDMA
{
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 & rs);
friend ostream &operator<< (ostream & os, const hasDMA & rs);
virtual void View();
};
#endif
對於實現文件,幾乎與書上的程序清單13.15相同,添加了View方法,在baseDMA類的View方法主要是顯示label和rating,而lacksDMA類的View方法新增顯示color,hasDMA類的View方法新增顯示style。
dma.cpp
#include "dma.h"
using namespace std;
#include <iostream>
#include <string>
ABC::ABC()
{}
ABC::~ABC()
{}
baseDMA::baseDMA(const char * l, int r)
{
label = new char[strlen(l) + 1];
strcpy_s(label, strlen(l) + 1, l);
rating = r;
}
baseDMA::baseDMA(const baseDMA &rs)
{
label = new char [strlen(rs.label) + 1];
strcpy_s(label, strlen(rs.label) + 1, rs.label);
rating = rs.rating;
}
baseDMA::~baseDMA()
{
delete [] label;
}
baseDMA & baseDMA::operator=(const baseDMA & rs)
{
if(this == &rs)
return *this;
delete [] label;
label = new char [strlen(rs.label) + 1];
strcpy_s(label, strlen(rs.label) + 1, rs.label)
rating = rs.rating;
return *this;
}
ostream &operator<<(ostream & os, const baseDMA & rs)
{
os << "Label: " << rs.label << endl;
os << "Rating: " << rs.rating << endl;
return os;
}
void baseDMA::View()
{
cout << "Label: " << label << endl;
cout << "Rating: " << rating << endl;
}
lacksDMA::lacksDMA(const char *c, const char *l, int r) : baseDMA(l ,r)
{
strncpy_s(color, 40, c, 39);
color[39] = '\0';
}
lacksDMA::lacksDMA(const char *c, const baseDMA &rs) : baseDMA(rs)
{
strncpy_s(color, 40, c, COL_LEN - 1);
color[COL_LEN - 1] = '\0';
}
ostream &operator<<(ostream & os, const lacksDMA & ls)
{
os << (const baseDMA &)ls;
os << "Color: " << ls.color << endl;
return os;
}
void lacksDMA::View()
{
baseDMA::View();
cout << "Color: " << color << endl;
}
hasDMA::hasDMA(const char *s, const char *l, int r) : baseDMA(l, r)
{
style = new char [strlen(s) + 1];
strcpy_s(style, strlen(s) + 1, s);
}
hasDMA::hasDMA(const char *s, const baseDMA &rs) : baseDMA(rs)
{
style = new char [strlen(s) + 1];
strcpy_s(style, strlen(s) + 1, s);
}
hasDMA::hasDMA(const hasDMA &hs) : baseDMA(hs)
{
style = new char [strlen(hs.style) + 1];
strcpy_s(style, strlen(hs.style) + 1, hs.style);
}
hasDMA::~hasDMA()
{
delete [] style;
}
hasDMA & hasDMA::operator=(const hasDMA & hs)
{
if(this == &hs)
return *this;
baseDMA::operator=(hs);
delete [] style;
style = new char[strlen(hs.style) + 1];
strcpy_s(style, strlen(hs.style) + 1, hs.style);
return *this;
}
ostream & operator<<(ostream & os, const hasDMA & hs)
{
os << (const baseDMA &)hs;
os << "Style: " << hs.style << endl;
return os;
}
void hasDMA::View()
{
baseDMA::View();
cout << "Style: " << style << endl;
}
以下檢測文件裏,多次使用了cin.ignore()函數,這是因爲在每次cin之後,緩衝區內部都會多出一個回車符,導致後面cin.getline()函數執行時,還不等你輸入信息,就直接彈出了後面的信息,使用cin.ignore()函數可以有效解決這個問題。
play.cpp
#include "dma.h"
using namespace std;
#include <iostream>
int main()
{
baseDMA shirt("Portabelly", 8);
lacksDMA balloon("red", "Blimpo", 4);
hasDMA map("Mercator", "Buffalo Keys", 5);
cout << "Displaying baseDMA object:\n";
cout << shirt << endl;
cout << "Displaying lackDMA object:\n";
cout << balloon << endl;
cout << "Displaying hasDMA object:\n";
cout << map << endl;
lacksDMA balloon2(balloon);
cout << "Result of lackDMA copy:\n";
cout << balloon2 << endl;
hasDMA map2;
map2 = map;
cout << "Result of hasDMA assignment:\n";
cout << map2 << endl;
cout << endl << "Shirt:\n";
shirt.View();
cout << endl << "Balloon:\n";
balloon.View();
cout << endl << "Map:\n";
map.View();
cout << endl << "Balloon2:\n";
balloon2.View();
cout << endl << "Map2:\n";
map2.View();
cout << "\nHow many inputs: ";
int number;
cin >> number;
cin.ignore();
for(int i=0; i<number; i++)
{
cout << "\n Enter '1' for baseDMA, '2' for lackDMA, '3' for hasDMA: " ;
char flag;
while (cin >> flag&& (flag != '1' && flag != '2' && flag != '3'))
{
cin.ignore();
cout << "Enter 1, 2, or 3: ";
}
cin.ignore();
if(flag == '1')
{
char *label = new char[20] ;
int rating;
cout << "Enter label: ";
cin.getline(label, 20);
cout << "Enter rating: ";
cin >> rating;
baseDMA * base = new baseDMA(label, rating);
cout << endl << "Input baseDMA: \n";
base->View();
}
else if (flag == '2')
{
char *label = new char[20];
int rating;
char *color = new char[40];
cout << "Enter label: ";
cin.getline(label, 20);
cout << "Enter rating: ";
cin >> rating;
cin.ignore();
cout << "Enter color: ";
cin.getline(color, 40);
lacksDMA *lacks = new lacksDMA(color, label, rating);
cout << endl << "Input lacksDMA: \n";
lacks->View();
}
else if (flag == '3')
{
char *label = new char[20];
int rating;
char *style = new char[40];
cout << "Enter label: ";
cin.getline(label, 20);
cout << "Enter rating: ";
cin >> rating;
cin.ignore();
cout << "Enter style: ";
cin.getline(style, 40);
hasDMA *has = new hasDMA(style, label, rating);
cout << endl << "Input hasDMA: \n";
has->View();
}
}
return 0;
}
4.
port.h
//直接按題給
#ifndef PORT_H
#define PORT_H
#include <iostream>
using namespace std;
class Port
{
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);
};
class VintagePort : public Port
{
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);
void Show() const ;
friend ostream &operator<<(ostream & os, const VintagePort & vp);
};
#endif
port.cpp
#include <iostream>
#include "port.h"
using namespace std;
#include <string>
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, 20, st);
bottles = b;
}
Port::Port(const Port &p)
{
brand = new char [strlen(p.brand) + 1];
strcpy_s(brand, strlen(p.brand) + 1, p.brand);
strcpy_s(style, 20, p.style);
bottles = p.bottles;
}
Port & Port::operator=(const Port & p)
{
brand = new char [strlen(p.brand) + 1];
strcpy_s(brand, strlen(p.brand) + 1, p.brand);
strcpy_s(style, 20, p.style);
bottles = p.bottles;
return *this;
}
Port & Port::operator+=(int b)
{
bottles += b;
return *this;
}
Port & Port::operator-=(int b)
{
bottles -= b;
return *this;
}
void Port::Show() const
{
cout << "Brand: " << brand << endl;
cout << "Style: " << style << endl;
cout << "Bottles: " << bottles << endl;
}
ostream& operator<<(ostream &os, const Port &p)
{
os << "Brand: " << p.brand << ", Style: " << p.style << ", Bottles: " << p.bottles << endl;
return os;
}
VintagePort::VintagePort()
{
nickname = new char [5];
strcpy_s(nickname, 5, "none");
year = 0;
}
VintagePort::VintagePort(const char *br, int b, const char *nn, int y)
{
nickname = new char [strlen(nn) + 1];
strcpy_s(nickname, strlen(nn) + 1, nn);
year = y;
}
VintagePort::VintagePort(const VintagePort &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)
{
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;
}
play.cpp
#include "port.h"
#include <iostream>
using namespace std;
#include <string>
int main()
{
Port wine1("Leoardo", "white", 15);
Port wine2 = wine1;
cout << "Now your wines: \n";
wine1.Show();
wine2.Show();
wine1+= 18;
wine2 -= 6;
cout << "After the change, your wine's bottles: \n";
cout << "Wine1: ";
wine1.BottleCount();
cout << "Wine2: ";
wine2.BottleCount();
cout << "And conclusion: \n";
cout << wine1 << endl;
cout << wine2 << endl;
cout << endl;
cout << "Now your wines upgrade to VintagePort class.\n";
VintagePort wine3("Elma", 21, "tww", 23);
VintagePort wine4;
(Port &)wine4 = (Port &)wine3;
(VintagePort &)wine4 = (VintagePort &)wine3;
cout << "Now the new wines are:\n";
wine3.Show();
wine4.Show();
wine3 += 17;
wine4 -= 5;
cout << "After the change, new wines' bottles:\n";
cout << "Wine3: ";
wine3.BottleCount();
cout << "Wine4: ";
wine4.BottleCount();
cout << "Conclusion: \n";
cout << wine3 << endl;
cout << wine4 << endl;
cout << endl;
return 0;
}