复习题
//14.6
//1
公有,北极熊是一种熊
私有,家里有厨房
公有,程序员是一种人
私有,马和驯马师的组合包含一个人
人,公有,司机是一个人
汽车,私有,司机有汽车
//2
Gloam::Gloam(int g, const char* s) : fb(s), glip(g) {}
Gloam::Gloam(int g, const Frabjous& f) : fb(f), glip(g) {}
void Gloam::tell() {
fb.tell();
std::cout << "glib: " << glib >> endl;
}
//3
Gloam::Gloam(int g, const char* s) : Frabjous(s), glip(g) {}
Gloam::Gloam(int g, const Frabjous& f) : Frabjous(f), glip(g) {}
void Gloam::tell() {
Frabjous::tell();
std::cout << "glib: " << glib >> endl;
}
//4
class Stack<Worker*> {
private:
enum { MAX = 10 };
Worker* items[MAX];
int top;
public:
Stack();
bool isempty();
bool isfull();
bool push()(const Workser*& item);
bool pop(Worker*& item);
};
//5
ArrayTP<string>arr_str;
StackTP<ArrayTP<double>>sck_arr_db;
ArrayTP<StackTP<Worker*>>arr_stk_workerp;
4个
//6
如果两条继承路线有相同的祖先,则类中将包含祖先成员的两个拷贝
将祖先类作为虚基类可以解决这种问题
编程练习
第一题
#pragma once
//wine.h
#include<valarray>
#include<string>
template<class T1,class T2>
class Pair {
private:
T1 a;
T2 b;
public:
T1& first();
T2& second();
T1 first()const { return a; }
T2 second()const { return b; }
Pair(const T1& aval, const T2& bval) :a(aval), b(bval) {}
Pair() {}
};
class Wine {
private:
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
std::string label;
PairArray pair;
int yr_num;
public:
Wine() :label("None"), yr_num(0),pair() {};
Wine(const char* l, int y, const int yr[], const int bot[]);
Wine(const char* l, int y);
void GetBottles();
const std::string& Label()const;
int sum()const;
void show()const;
};
//wine.cpp
#include<iostream>
#include"wine.h"
using namespace std;
Wine::Wine(const char* l, int y, const int yr[], const int bot[])
:label(l), yr_num(y) {
ArrayInt a(y);
ArrayInt b(y);
for (int i = 0; i < y; i++) {
a[i] = yr[i];
b[i] = bot[i];
}
pair.first() = a;
pair.second() = b;
}
Wine::Wine(const char* l, int y) :label(l), yr_num(y) {
ArrayInt a(y);
ArrayInt b(y);
for (int i = 0; i < y; i++) {
a[i] = 0;
b[i] = 0;
}
pair.first() = a;
pair.second() = b;
}
void Wine::GetBottles() {
ArrayInt a(yr_num);
ArrayInt b(yr_num);
cout << "Enter " << label << " data for " << yr_num << " year(s):" << endl;
for (int i = 0; i < yr_num; i++) {
cout << "Enter year: ";
cin >> a[i];
cout << "Enter bottles for that years: ";
cin >> b[i];
}
pair.first() = a;
pair.second() = b;
}
const string& Wine::Label()const {
return label;
}
int Wine::sum()const {
int sum = 0;
for (int i = 0; i < yr_num; i++)
sum += pair.second()[i];
return sum;
}
void Wine::show()const {
cout << "Wine: " << label << endl;
cout << "\tyear\tBottles" << endl;
for (int i = 0; i < yr_num; i++)
cout << "\t" << pair.first()[i] << "\t" << pair.second()[i] << endl;
}
template<class T1, class T2>
T1& Pair<T1, T2>::first() {
return a;
}
template<class T1, class T2>
T2& Pair<T1, T2>::second() {
return b;
}
//main.cpp
#include"wine.h"
#include<iostream>
using namespace std;
int main() {
cout << "Enter name of wine: ";
char lab[50];
cin.getline(lab, 50);
cout << "Enter number of years:";
int years;
cin >> years;
Wine holding(lab, years);
holding.GetBottles();
holding.show();
const int YEARS = 3;
int y[YEARS] = { 1993,1995,1998 };
int b[YEARS] = { 48,60,72 };
Wine more("Gushing Grape Red", YEARS, y, b);
more.show();
cout << "Total bottles for " << more.Label()
<< ": " << more.sum() << endl;
cout << "Bye!";
return 0;
}
第二题
测试程序不变,因此只给出类声明和方法定义
#pragma once
//wine.h
#include<valarray>
#include<string>
template<class T1,class T2>
class Pair {
private:
T1 a;
T2 b;
public:
T1& first();
T2& second();
T1 first()const { return a; }
T2 second()const { return b; }
Pair(const T1& aval, const T2& bval) :a(aval), b(bval) {}
Pair() {}
};
typedef std::valarray<int> ArrayInt;
typedef Pair<ArrayInt, ArrayInt> PairArray;
class Wine :std::string,Pair<ArrayInt, ArrayInt>{
private:
int yr_num;
public:
Wine() :std::string("None"), yr_num(0),Pair() {};
Wine(const char* l, int y, const int yr[], const int bot[]);
Wine(const char* l, int y);
void GetBottles();
const std::string& Label()const;
int sum()const;
void show()const;
};
//wine.cpp
#include<iostream>
#include"wine.h"
using namespace std;
Wine::Wine(const char* l, int y, const int yr[], const int bot[])
:string(l), yr_num(y) {
ArrayInt a(y);
ArrayInt b(y);
for (int i = 0; i < y; i++) {
a[i] = yr[i];
b[i] = bot[i];
}
Pair::first() = a;
Pair::second() = b;
}
Wine::Wine(const char* l, int y) :string(l), yr_num(y) {
ArrayInt a(y);
ArrayInt b(y);
for (int i = 0; i < y; i++) {
a[i] = 0;
b[i] = 0;
}
Pair::first() = a;
Pair::second() = b;
}
void Wine::GetBottles() {
ArrayInt a(yr_num);
ArrayInt b(yr_num);
cout << "Enter " << (const string&)*this << " data for " << yr_num << " year(s):" << endl;
for (int i = 0; i < yr_num; i++) {
cout << "Enter year: ";
cin >> a[i];
cout << "Enter bottles for that years: ";
cin >> b[i];
}
Pair::first() = a;
Pair::second() = b;
}
const string& Wine::Label()const {
return (const string&)*this;
}
int Wine::sum()const {
int sum = 0;
for (int i = 0; i < yr_num; i++)
sum += Pair::second()[i];
return sum;
}
void Wine::show()const {
cout << "Wine: " << (const string&)*this << endl;
cout << "\tyear\tBottles" << endl;
for (int i = 0; i < yr_num; i++)
cout << "\t" << Pair::first()[i] << "\t" << Pair::second()[i] << endl;
}
template<class T1, class T2>
T1& Pair<T1, T2>::first() {
return a;
}
template<class T1, class T2>
T2& Pair<T1, T2>::second() {
return b;
}
第三题
大坑,因为书上只说了一遍,没有重复三遍以上(狗头)因此我压根没注意到。
因为模板类和模板函数只有在使用时才会实例化。当模板被使用时,编译器需要函数的所有代码,来用合适的类型去构建正确的函数,而如果函数的实现写在一个独立的源文件中,这些文件是不可见的,因此会出错。LNK2019。
总之队列的模板声明和函数定义放在一起。
#pragma once
//worker.h
#include<string>
class Worker {
private:
std::string fullname;
long id;
protected:
virtual void Data()const;
virtual void Get();
public:
Worker() :fullname("no name"), id(0L) {};
Worker(const std::string& s, long n) :fullname(s), id(n) {};
virtual ~Worker() = 0;
virtual void Set() = 0;
virtual void Show()const = 0;
};
class Waiter :virtual public Worker {
int panache;
protected:
void Data()const;
void Get();
public:
Waiter() :Worker(), panache(0) {};
Waiter(const std::string& s,long n,int p = 0)
:Worker(s,n), panache(p) {}
Waiter(const Worker& w, int p = 0) :Worker(w), panache(p) {}
void Set();
void Show()const;
};
class Singer :virtual public Worker {
protected:
enum{other,alto,contralto,soprano,bass,baritone,tenor};
enum{Vtypes=7};
void Data()const;
void Get();
private:
static char* pv[Vtypes];
int voice;
public:
Singer() :Worker(), voice(other) {}
Singer(const std::string& s, long n, int v = other)
:Worker(s, n), voice(v) {}
Singer(const Worker& w, int v = other)
:Worker(w), voice(v) {}
void Set();
void Show()const;
};
class SW :public Singer, public Waiter {
protected:
void Data()const;
void Get();
public:
SW() {}
SW(const std::string& s, long n, int p = 0, int v = other)
:Worker(s, n), Waiter(s, n, p), Singer(s, n, v) {}
SW(const Worker& w, int p = 0, int v = other)
:Worker(w), Waiter(w, p), Singer(w, v) {}
SW(const Worker& w, int p = 0)
:Worker(w), Waiter(w, p), Singer(w) {}
void Set();
void Show()const;
};
//worker.cpp
#include<iostream>
#include"worker.h"
using namespace std;
//Worker methods
Worker::~Worker() {}
void Worker::Get() {
getline(cin, fullname);
cout << "Enter worker's ID: ";
cin >> id;
while (cin.get() != '\n')
continue;
}
void Worker::Data()const {
cout << "Name: " << fullname << endl;
cout << "Employee ID: " << id << endl;
}
//Waiter methods
void Waiter::Set() {
cout << "Enter waiter's name: ";
Worker::Get();
Get();
}
void Waiter::Show()const {
cout << "Category: waiter\n";
Worker::Data();
Data();
}
void Waiter::Data() const {
cout << "Panache rating: " << panache << endl;
}
void Waiter::Get() {
cout << "Enter waiter's panache rating: ";
cin >> panache;
while (cin.get() != '\n')
continue;
}
//Singer methods
char* Singer::pv[Singer::Vtypes] =
{ "other","alto","contralto","soprano","bass","baritone","tenor" };
void Singer::Set() {
cout << "Enter singer's name: ";
Worker::Get();
Get();
}
void Singer::Data()const {
cout << "Vocla range: " << pv[voice] << endl;
}
void Singer::Show()const {
cout << "Category: singer\n";
Worker::Data();
Data();
}
void Singer::Get() {
cout << "Enter number for singer's vocal range:\n";
int i;
for (i = 0; i < Vtypes; i++) {
cout << i << ": " << pv[i] << " ";
if (i % 4 == 3)
cout << endl;
}
if (i % 4 != 0)
cout << endl;
cin >> voice;
while (cin.get() != '\n')
continue;
}
//SW methods
void SW::Data()const {
Singer::Data();
Waiter::Data();
}
void SW::Get() {
Waiter:: Get();
Singer::Get();
}
void SW::Set() {
cout << "Enter singing waiter's name: ";
Worker::Get();
Get();
}
void SW::Show()const {
cout << "Category: singing waiter\n";
Worker::Data();
Data();
}
//queuetpyue.cpp
//队列的设计参考第12章程序清单12.10
//因为模板类和模板函数只有在使用时才会实例化。
//当模板被使用时,编译器需要函数的所有代码,来用合适的类型去构建正确的函数,
//而如果函数的实现写在一个独立的源文件中,这些文件是不可见的,因此会出错。
template<class T>
class QueueTP {
enum { MAX = 10 };
struct Node { T item; Node* next; };
Node* front;
Node* rear;
int items;
const int qsize = MAX;
QueueTP<T>(const QueueTP<T>& q) : qsize(0) {}
QueueTP<T>& operator=(const QueueTP<T>& q) { return *this; }
public:
QueueTP(int qs = MAX);
~QueueTP();
bool isempty()const;
bool isfull()const;
int queuecount()const { return items; }
bool enqueue(const T& item);
bool dequeue(T& item);
};
template<class T>
QueueTP<T>::QueueTP(int qs) : qsize(qs) {
front = rear = nullptr;
items = 0;
}
template<class T>
QueueTP<T>::~QueueTP() {
Node* temp;
while (front != nullptr) {
temp = front;
front = front->next;
delete temp;
}
}
template<class T>
bool QueueTP<T>::isempty()const {
return items == 0;
}
template<class T>
bool QueueTP<T>::isfull()const {
return items == qsize;
}
template<class T>
bool QueueTP<T>::enqueue(const T& item) {
if (isfull())
return false;
Node* add = new Node;
add->next = nullptr;
add->item = item;
items++;
if (front == nullptr)
front = add;
else
rear->next = add;
rear = add;
return true;
}
template<class T>
bool QueueTP<T>::dequeue(T& item) {
if (front == nullptr)
return false;
item = front->item;
items--;
Node* temp = front;
front = front->next;
delete temp;
if (items == 0)
rear = nullptr;
return true;
}
//main.cpp
#include"queuetpyue.h"
#include"worker.h"
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE = 5;
int main() {
QueueTP<Worker*> qw(SIZE);
Worker* lolas[SIZE];
int ct;
for (ct = 0; ct < SIZE; ct++) {
char choice;
cout << "Enter the employee category:\n"
<< "w: waiter s: singer "
<< "t: Singing Waiter q: quit\n";
cin >> choice;
while (strchr("wstq", choice) == nullptr) {
cout << "Please enter a w, s, t or q: ";
cin >> choice;
}
if (choice == 'q')
break;
switch (choice) {
case'w':lolas[ct]=new Waiter; break;
case's':lolas[ct]=new Singer; break;
case't':lolas[ct]=new SW; break;
}
cin.get();
lolas[ct]->Set();
cout << "Enqueue! #" << ct << endl;
lolas[ct]->Show();
qw.enqueue(lolas[ct]);
}
cout << "\nHere is your staff(dequeue):\n";
for (int i = 0; i < ct; i++) {
qw.dequeue(lolas[i]);
lolas[i]->Show();
delete lolas[i];
}
cout << "Bye!\n";
return 0;
}
第四题
//abc.h
#include<string>
using std::string;
class Person {
string fname;
string lname;
protected:
virtual void GetData();
public:
Person() :fname("no name"), lname() {}
Person(string& f, string& l) :fname(f), lname(l) {}
virtual ~Person() {}
virtual void Show();
virtual void Set();
};
class Gunslinger :virtual public Person {
double draw;
int kehen;
protected:
void GetData();
public:
Gunslinger() :Person(), draw(0.0), kehen(0) {}
Gunslinger(string& f, string& l, double time, int kh)
:Person(f, l), draw(time), kehen(kh) {}
Gunslinger(Person& p, double time, int kh)
:Person(p), draw(time), kehen(kh) {}
double Draw() { return draw; }
void Show();
void Set();
};
class PokerPlayer :virtual public Person {
int puke;
protected:
void GetData();
public:
PokerPlayer() :Person(), puke(1) {}
PokerPlayer(string& f, string& l, int pk) :Person(f, l), puke(pk) {}
PokerPlayer(Person& p, int pk) :Person(p), puke(pk) {}
int Draw();
void Show();
void Set();
};
class BadDude :public Gunslinger, public PokerPlayer {
protected:
void GetData();
public:
BadDude() :Person(), Gunslinger(), PokerPlayer() {}
BadDude(string& f, string& l, double time, int kh)
:Person(f, l), Gunslinger(f, l, time, kh) {}
BadDude(Person& p, double time, int kh)
:Person(p), Gunslinger(p, time, kh) {}
double Gdraw() { Gunslinger::Draw(); }
int Cdraw() { PokerPlayer::Draw(); }
void Show();
void Set();
};
//abc.cpp
#include<iostream>
#include"abc.h"
#include<cstdlib>
#include<ctime>
using namespace std;
void Person::GetData() {
cout << "输入名和姓:";
cin >> fname >> lname;
}
void Person::Show() {
cout << "此人的名字:" << lname
<< " " << fname << endl;
}
void Person::Set() {
GetData();
}
void Gunslinger::GetData() {
cout << "输入拔枪时间(double):";
cin >> draw;
cout << "输入刻痕数(int):";
cin >> kehen;
}
void Gunslinger::Show() {
Person::Show();
cout << "拔枪时间:" << draw << endl;
cout << "刻痕数:" << kehen << endl;
}
void Gunslinger::Set() {
Person::GetData();
GetData();
}
void PokerPlayer::GetData() {
cout << "输入扑克牌数(1 to 53):";
cin >> puke;
}
int PokerPlayer::Draw() {
srand(time(0));
return rand() % (53) + 1;
}
void PokerPlayer::Show() {
Person::Show();
cout << "扑克牌:" << puke << endl;
}
void PokerPlayer::Set() {
Person::GetData();
GetData();
}
void BadDude::GetData() {
Person::GetData();
Gunslinger::GetData();
PokerPlayer::GetData();
}
void BadDude::Show() {
Gunslinger::Show();
cout << "扑克牌:" << PokerPlayer::Draw();
}
void BadDude::Set() {
GetData();
}
//main.cpp
#include"abc.h"
#include<iostream>
#include<cstring>
using namespace std;
const int SIZE = 5;
int main() {
Person* lolas[SIZE];
int ct;
for (ct = 0; ct < SIZE; ct++) {
char choice;
cout << "Enter the person's category:\n"
<< "a: Person b: Gunslinger "
<< "c: PokerPlayer " << endl
<< "d:BadDude q: quit\n";
cin >> choice;
while (strchr("abcdq", choice) == nullptr) {
cout << "Please enter a, b, c ,d or q: ";
cin >> choice;
}
if (choice == 'q')
break;
switch (choice) {
case'a':lolas[ct] = new Person; break;
case'b':lolas[ct] = new Gunslinger; break;
case'c':lolas[ct] = new PokerPlayer; break;
case'd':lolas[ct] = new BadDude; break;
}
cin.get();
lolas[ct]->Set();
cout << endl;
}
cout << "\nHere are the peoples:\n";
for (int i = 0; i < ct; i++) {
cout << "#" << i << endl;
lolas[i]->Show();
cout << endl;
delete lolas[i];
}
cout << "Bye!\n";
return 0;
}
第五题
//emp.h
#include<iostream>
#include<string>
using namespace std;
class abstr_emp {
string fname;
string lname;
string job;
public:
abstr_emp() :fname("no"), lname("name"), job("no job") {}
abstr_emp(const string& fn, const string& ln, const string& j)
:fname(fn), lname(ln), job(j) {}
//此处const表示此函数不会修改传递的值
//函数后的const表示不会修改类的数据成员
virtual void ShowAll()const;
virtual void SetAll();
friend ostream& operator<<(ostream& os, const abstr_emp& a);
virtual ~abstr_emp() = 0 {}
};
class employee :public abstr_emp {
public:
employee() :abstr_emp() {}
employee(const string& fn, const string& ln, const string& j)
:abstr_emp(fn, ln, j) {}
void ShowAll()const;
void SetAll();
};
class manager :virtual public abstr_emp {
private:
int inchargeof;
protected:
int Inchargeof()const { return inchargeof; }//output
int& Inchargeof() { return inchargeof; }//input
//只读(const)和非只读函数可以形成重载关系.此时,对于只读对象,只能调用只读函数
//而非只读对象会优先选择非只读函数.
public:
manager() :abstr_emp(), inchargeof(0) {}
manager(const string& fn, const string& ln, const string& j,
int ico = 0) :abstr_emp(fn, ln, j), inchargeof(ico) {}
manager(const abstr_emp& a, int ico = 0) :abstr_emp(a), inchargeof(ico) {}
manager(const manager& m)
:abstr_emp(m), inchargeof(m.inchargeof) {}
virtual void ShowAll()const;
virtual void SetAll();
};
class fink :virtual public abstr_emp {
string reportsto;
protected:
const string Reportsto()const { return reportsto; }
string& Reportsto() { return reportsto; }
public:
fink() :abstr_emp(), reportsto("???") {}
fink(const string& fn, const string& ln, const string& j,
const string& rt) :abstr_emp(fn, ln, j), reportsto(rt) {}
fink(const abstr_emp& e, const string& rt) :abstr_emp(e), reportsto(rt) {}
fink(const fink& f) :abstr_emp(f), reportsto(f.reportsto) {}
virtual void ShowAll()const;
virtual void SetAll();
};
class highfink :public manager, public fink {
public:
highfink() :abstr_emp(), manager(), fink() {}
highfink(const string& fn, const string& ln, const string& j,
const string& rt, int ico)
:abstr_emp(fn, ln, j), manager(fn, ln, j, ico), fink(fn, ln, j, rt) {}
highfink(const abstr_emp& a, const string& rt, int ico)
:abstr_emp(a), manager(a, ico), fink(a, rt) {}
highfink(const fink& f, int ico)
:abstr_emp(f), manager(f, ico), fink(f) {}
highfink(const manager& m, const string& rt)
:abstr_emp(m), manager(m), fink(m, rt) {}
highfink(const highfink& h)
:abstr_emp(h), manager(h), fink(h) {}
virtual void ShowAll()const;
virtual void SetAll();
};
//emp.cpp
#include"emp.h"
using namespace std;
void abstr_emp::ShowAll()const {
cout << "Name: " << fname << " " << lname << endl;
cout << "job: " << job << endl;
}
void abstr_emp::SetAll() {
cout << "Enter the data:\n" << "first name: ";
cin >> fname;
cout << "lastname: ";
cin >> lname;
cout << "job: ";
cin >> job;
}
ostream& operator<<(ostream& os, const abstr_emp& a) {
os << a.fname << " " << a.lname << endl;
return os;
}
void employee::ShowAll()const {
abstr_emp::ShowAll();
}
void employee::SetAll() {
abstr_emp::SetAll();
}
void manager::ShowAll()const {
abstr_emp::ShowAll();
cout << "In charge of: " << inchargeof << endl;
}
void manager::SetAll() {
abstr_emp::SetAll();
cout << "in charge of: ";
cin >> inchargeof;
}
void fink::ShowAll()const {
abstr_emp::ShowAll();
cout << "reports to: " << reportsto << endl;
}
void fink::SetAll() {
abstr_emp::SetAll();
cout << "reports to: ";
cin >> reportsto;
}
void highfink::ShowAll()const {
abstr_emp::ShowAll();
cout << "In charge of: " << manager::Inchargeof() << endl;
cout << "reports to: " << fink::Reportsto() << endl;
}
void highfink::SetAll() {
abstr_emp::SetAll();
cout << "in charge of: ";
cin >> manager::Inchargeof();
cout << "reports to: ";
cin >> fink::Reportsto();
}
//main.cpp
#include"emp.h"
using namespace std;
#include<iostream>
int main() {
employee em("Trip", "Harris", "Thumper");
cout << em << endl;
em.ShowAll();
cout << endl;
manager ma("Amorphia", "Spindragon", "Nuancer", 5);
cout << ma << endl;
ma.ShowAll();
cout << endl;
fink fi("Matt", "Oggs", "Oiler", "Juno Barr");
cout << fi << endl;
fi.ShowAll();
cout << endl;
highfink hf(ma, "Curly Kew");
hf.ShowAll();
cout << endl;
cout << "Press a key for next phase:\n";
cin.get();
highfink hf2;
hf2.SetAll();
cout << endl;
cout << "Using an abstr_emp* pointer:\n\n";
abstr_emp* tri[4] = { &em,&fi,&hf,&hf2 };
for (int i = 0; i < 4; i++) {
tri[i]->ShowAll();
cout << endl;
}
return 0;
}
a:没有用到指针和new分配内存,因此默认赋值运算符使用的浅拷贝可以满足需要,不需要自己定义完成深拷贝
b:定义为虚表示接下来会在派生类重新定义它们,在使用基类指针表示派生类的时候,可以正确调用对象的函数
c:以虚基类继承时,MI(多重继承)就不会继承多个相同的对象,在MI时,继承的类中,有相同祖先的所有继承虚基类的类产生一个祖先对象,继承的不是虚基类的各产生一个祖先对象
d:所有需要的数据已经在继承的类中包含
e:此题需要的<<输出均为输出名字即可,abstr_emp的友元可供派生类使用,足以满足要求,如果题目要求使用<<时输出不同的信息,自然可以在每个类分别定义
f:实际上因为基类早已被定义为抽象类,因此不允许使用抽象类数组,如果去掉析构的=0,那么可以运行,但是显然数组的四个成员会被截留成基类,也就是只剩下基类数据,调用ShowAll()也是调用基类的ShowAll(),只显示name和job