复习题
//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