纯原创 转载请注明出处:http://blog.youkuaiyun.com/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;
}
15.8 15.9 15.10
#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
不会发生任何意外