c++primer(第五版) 第十五章 面向对象程序设计习题答案

纯原创    转载请注明出处: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;
}



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

不会发生任何意外


你可能感兴趣的:(C++)