纯原创 转载请注明出处:http://blog.csdn.net/axuan_k
略过书上有现成代码的题目
15.1 15.2
15.1 虚成员是基类中的概念 基类中的某些函数希望它的派生类能够重新定义自己的版本 则基类中这样的函数被称为虚函数(虚成员) 15.2 private的成员:只有本类的对象或友元函数或友元类的对象能调用它 protected的成员:除上述之外,本类的派生类的对象也能调用它
15.4
#include<iostream> using namespace std; // 15.4 class Base{}; class b1:public b1{}; //不能继承自己 class b2:private Base{}; //这是一个派生类的定义语句而不是声明语句 class b3:public Base{} ; //派生类的声明应与普通类的声明一样,不该有列表 int main(){ return 0; }
#include<iostream> using namespace std; int main(){ // 15.8 // 静态类型的成员在进行编译的时候就知道它的类型了 // 动态类型的成员直到程序运行时才直到它自己的类型 // 15.9 // 基类对象的指针指向子类对象 // 基类对象的引用引用子类对象 // 15.10 // read()函数的第一个参数虽然是istream类型的引用 // 但input对象是istream子类ifstream的对象, // 即这个参数是动态类型的,所有可以正常工作 return 0; }
15.12 15.13 15.14
#include<iostream> #include<string> using namespace std; class base { public: string name() { return basename; } virtual void print(ostream &os) { os << basename<<endl; } private: string basename="sssss"; }; class derived : public base { public: void print(ostream &os) override { base::print(os); //改成这样 os << " " << i<<endl; } private: int i=2; }; int main(){ // 15.12 // 有必要,因为override和final的定义并不矛盾 // override是覆盖基类同名的函数成员 // 而final则表示该函数成员不能继续继承下去 // 可以并且有必要存在两点都满足的成员函数 // 15.13 // 会产生无限递归,在派生类derived中paint方法会重复调用自己 // 从而产生递归,应该通过使用作用域运算符强迫调用基类的paint函数 // 即应改为: // Base::paint(os); derived a; a.print(cout); cout<<endl; // 15.14 base bobj; base *bp1=&bobj; base &br1=bobj; derived dobj; base *bp2=&dobj; base &br2=dobj; bobj.print(cout); //调用base::paint dobj.print(cout); //调用derived::paint cout<<bp1->name()<<endl; //父类对象bobj的name cout<<bp2->name()<<endl; //子类对象dobj继承来的name br1.print(cout); //调用base::paint br2.print(cout); //调用derived::paint return 0; }
15.15 15.16 15.17
#include<iostream> #include<string> using namespace std; // 15.15 class Quote{ public: Quote()=default; Quote(const string& book,double p):bookNo(book),price(p){} string isbn()const{return bookNo;} virtual double net_price(size_t n)const{ return n*price; } private: string bookNo; protected: double price=0.0; }; class Disc_quote:public Quote{ public: Disc_quote()=default; Disc_quote(const string& name,double p,size_t qty,double disc):Quote(name,p),quantity(qty),discount(disc){} double net_price(size_t)const =0; protected: size_t quantity=0; double discount=0.0; }; class Bulk_quote:public Disc_quote{ public: Bulk_quote()=default; Bulk_quote(const string& name,double p,size_t qty,double disc):Disc_quote(name,p,qty,disc){} // 15.16 double net_price(size_t cnt)const override{ if(cnt>=quantity) return cnt*(1-discount)*price; else return cnt*price; } }; int main(){ // 15.17 Quote a("asdsad",1.2); Disc_quote b("sasda",1.2,123,2.2); //D:\3.22\asd.cpp|45|error: cannot declare variable 'b' to be of abstract type 'Disc_quote'| Bulk_quote c("sasda",1.2,123,2.2); return 0; }
15.18 15.19
#include <iostream> #include<string> #include<sstream> using namespace std; int main() { // 15.18 Base *p = &d1; //legal p = &d2; //illegal p = &d3; //illegal p = &dd1; //legal p = &dd2; //illegal p = &dd3; //illegal //只有第一个和第四个是正确的 这里是 在用户代码中 派生类向基类的转换(指针) //书中原话:只有当D公有的继承B时,用户代码 才能使用派生类向基类转换 // 15.19 // 因为转换发生在函数中,所有这里用到书中第二条规则:不论D以什么方式继承B,D // 的成员函数和友元都能使用派生类向基类的转换 // 所以所有继承于Base的类Pub_Derv,Priv_Derv,Prot_Derv都可以转换 // Derived_from_Public ,Derived_from_Protected 这两个类也可以转换两次得到 return 0; }
15.23
#include <iostream> #include <string> class Base { public: virtual int fcn(){ std::cout << "Base::fcn()\n"; return 0; } }; class D1 : public Base { public: //去掉参数列表中的int 同时可在()后面添加override int fcn() override { std::cout << "D1::fcn()\n";return 0; } virtual void f2() { std::cout << "D1::f2()\n"; } }; class D2 : public D1 { public: int fcn(int); int fcn() override { std::cout << "D2::fcn()\n";return 0; } void f2() override { std::cout << "D2::f2()\n"; } }; int main() { Base bobj; D1 d1obj; D2 d2obj; Base *bp1 = &bobj, *bp2 = &d1obj, *bp3 = &d2obj; bp1->fcn(); //Base::fcn() bp2->fcn(); // D1::fcn() bp3->fcn(); // D2::fcn() D1 *d1p = &d1obj; D2 *d2p = &d2obj; //bp2->f2(); //同书上 Base没有f2() //d1p->f2(); // D1::f2() //d2p->f2(); // D2::f2() return 0; }
15.24
基类需要虚析构函数 在这些类完成动态绑定的同时,通过调用正确的析构函数来执行正确的销毁操作
15.25
会产生编译错误 因为Bulk_quote中也有默认构造函数,而这个构造函数的状态是由Disc_quote的默认构造函数决定的; Bulk_quote删除了默认构造函数,同时存在另一个4个参数的构造函数,所以编译器也不会再合成默认构造函数
15.26
#include<iostream> #include<string> using namespace std; // 15.15 class Quote{ public: Quote(){cout<<"Quote()"<<endl;}; Quote(const string& book,double p):bookNo(book),price(p){ cout<<"Quote(const string& book,double p)"<<endl; } Quote(const Quote& q):bookNo(q.bookNo),price(q.price){ cout<<"Quote(const Quote& q)"<<endl; } Quote& operator=(const Quote& q){ cout<<"Quote& operator=(const Quote& q)"<<endl; bookNo=q.bookNo; price=q.price; return *this; } virtual ~Quote(){cout<<"virtual ~Quote()"<<endl;} string isbn()const{return bookNo;} virtual double net_price(size_t n)const{ return n*price; } private: string bookNo; protected: double price=0.0; }; class Disc_quote:public Quote{ public: Disc_quote()=default; Disc_quote(const string& name,double p,size_t qty,double disc):Quote(name,p),quantity(qty),discount(disc){} Disc_quote(const Disc_quote& dq):Quote(dq),quantity(dq.quantity),discount(dq.discount){} Disc_quote& operator=(const Disc_quote& dq){ Quote::operator=(dq); quantity=dq.quantity; discount=dq.discount; return *this; } double net_price(size_t)const =0; protected: size_t quantity=0; double discount=0.0; }; class Bulk_quote:public Disc_quote{ public: Bulk_quote(){cout<<"Bulk_quote()"<<endl;}; Bulk_quote(const string& name,double p,size_t qty,double disc):Disc_quote(name,p,qty,disc){ cout<<"Bulk_quote(const string& name,double p,size_t qty,double disc)"<<endl; } Bulk_quote(const Bulk_quote& bq):Disc_quote(bq){ cout<<"Bulk_quote(const Bulk_quote& bq)"<<endl; } Bulk_quote& operator=(const Bulk_quote& bq){ cout<<"Bulk_quote& operator=(const Bulk_quote& bq)"<<endl; Disc_quote::operator=(bq); return *this; } ~Bulk_quote()override{ cout<<"~Bulk_quote()"<<endl; } double net_price(size_t cnt)const override{ if(cnt>=quantity) return cnt*(1-discount)*price; else return cnt*price; } }; int main(){ // 15.17 Quote a("asdsad",1.2); Bulk_quote c("sasda",1.2,123,2.2); cout<<endl<<endl; Bulk_quote d(c); cout<<endl<<endl; c=d; cout<<endl<<endl; return 0; }
15.27
上题加上using声明即可
15.28 15.29
#include<iostream> #include<vector> #include<memory> #include"Bulk_quote.h" using namespace std; int main(){ double ans1=0.0,ans2=0.0; vector<Quote>vec1; vector<shared_ptr<Quote> >vec2; vec1.push_back(Quote("11111-1",3.3)); vec1.push_back(Bulk_quote("2222-2",3.3,2,0.5)); vec2.push_back(make_shared<Quote>("11111-1",3.3)); vec2.push_back(make_shared<Bulk_quote>("2222-2",3.3,2,0.5)); for(int i=0;i<vec1.size();i++){ ans1+=vec1[i].net_price(2); ans2+=vec2[i]->net_price(2); } cout<<ans1<<" "<<ans2<<endl; //13.2 9.9 //答案不一样 因为vec1保存的全部是Quote的对象(静态类型) 也就是说Bulk_quote强行转换成了Quote //而vec2保存的是(动态类型) 转换的仅是指针 return 0; }
15.31 15.32 15.33
15.31 (a) OrQuery, AndQuery, NotQuery, WordQuery (b) OrQuery, AndQuery, NotQuery, WordQuery (c) OrQuery, AndQuery, WordQuery 15.32 拷贝,移动,赋值和销毁使用的都是编译器自动合成的版本 拷贝,赋值:新对象的智能指针q将指向原对象中q指向的Query_base体系下的对象 所以成员智能指针的use count +1 移动:原对象的q(智能指针)指向空nullptr,新对象指向原对象中成员q(智能指针)指向的对象 use count不变 销毁:对象成员q(智能指针)的use count -1,如果use count为0 则它指向的对象就会自动销毁 15.33 Query_base是一个纯虚类,没有自己的对象
15.34
15.34 (a) WordQuery 三次 "fiery","bird" and "wind" Query 三次 "fiery","bird" and "wind" AndQuery 一次 BinaryQuery 一次 Query 一次 &运算结果 OrQuery 一次 BinaryQuery 一次 Query 一次 |运算结果 (b) BinaryQuery BinaryQuery Query WordQuery Query WordQuery Query WordQuery (c) Query::eval() Query_base的派生类的各种eval
15.35
Query.h
#ifndef QUERY #define QUERY #include<string> #include<memory> #include"Query_base.h" #include"WordQuery.h" #include"QueryResult.h" using namespace std; class Query{ friend operator|(const Query& l,const Query& r); friend operator&(const Query& l,const Query& r); friend operator~(const Query& obj); public: Query(const string& str):q(new WordQuery(str)){} QueryResult eval(const TextQuery& tq)const{ return q->eval(tq); } string rep()const{ return q->rep(); } private: shared_ptr<Query_base>q; }; #endif // QUERY
Query_base.h
#ifndef QUERY_BASE #define QUERY_BASE #include<string> #include"QueryResult.h" using namespace std; class Query_base{ public: virtual QueryResult eval(const TextQuery&)const=0; virtual string rep()const =0; virtual ~Query_base(){}; }; #endif // QUERY_BASE
15.38
BinaryQuery a = Query("fiery") & Query("bird"); //不合法 纯虚类没有对象 AndQuery b = Query("fiery") & Query("bird"); //不合法 &操作后返回的是Query的对象 无法转换为AndQuery的对象 OrQuery c = Query("fiery") & Query("bird"); //不合法 &操作后返回的是Query的对象 无法转换为OrQuery的对象
15.42
不会发生任何意外