C++ Primer第5版 第十九章课后练习答案

练习19.1

void* operator new(size_t size) {
    if (void* mem = malloc(size)) 
        return mem;
    else
        throw std::bad_alloc();
}

void operator delete(void* mem)noexcept {
    free(mem);
}

练习19.2

inline void* StrVec::operator new(size_t size)
{
    if (void* mem = malloc(size))
        return mem;
    else
        throw std::bad_alloc();
}
inline void StrVec::operator delete(void* mem) noexcept
{
    std::free(mem);
}

练习19.3

(b)失败,基类指针要转化为派生类指针,基类指针需指向派生类;

(c)失败,A *pa = new D具有二义性,A是D的一个二义基类。

练习19.4

A *pa = new C;
    try{
        const C &c = dynamic_cast<const C&>(*pa);
    }catch(std::bad_cast &e){
        std::cout << e.what() << std::endl;
    }

练习19.5

我们想使用基类对象的指针或引用执行某个派生类操作并且该操作不是虚函数时可以使用RTTI运算符

练习19.6

int main(int argc, char const* argv[])
{
    chapter15::Query_base* pb1 = new chapter15::AndQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    chapter15::Query_base* pb2 = new chapter15::OrQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    if (chapter15::AndQuery* aq = dynamic_cast<chapter15::AndQuery*>(pb1)) {
        cout << "aq成功";
    }
    else {
        cout << "aq失败";
    }

    if (chapter15::OrQuery* oq = dynamic_cast<chapter15::OrQuery*>(pb2)) {
        cout << "oq成功";
    }
    else {
        cout << "oq失败";
    }
    return 0;
}

练习19.7

int main(int argc, char const* argv[])
{
    chapter15::Query_base* pb1 = new chapter15::AndQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    chapter15::Query_base* pb2 = new chapter15::OrQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    try {
        chapter15::AndQuery& aq = dynamic_cast<chapter15::AndQuery&>(*pb1);
        cout << "aq成功";
    }
    catch(std::bad_cast) {
        cout << "aq失败";
    }

    try {
        chapter15::OrQuery& aq = dynamic_cast<chapter15::OrQuery&>(*pb2);
        cout << "oq成功";
    }
    catch (std::bad_cast) {
        cout << "oq失败";
    }
    return 0;
}

练习19.8

int main(int argc, char const* argv[])
{
    chapter15::Query_base* pb1 = new chapter15::AndQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    chapter15::Query_base* pb2 = new chapter15::OrQuery(chapter15::Query("value1"), chapter15::Query("value2"));
    if (typeid(*pb1) == typeid(*pb2)) {
        cout << "pb1和pb2指向同一种类型" << endl;
        if (typeid(*pb1) == typeid(chapter15::AndQuery))
            cout << "这种类型是AndQuery" << endl;
        else
            cout << "这种类型不是AndQuery" << endl;
    }    
    else
        cout << "pb1和pb2不指向同一种类型" << endl;

    return 0;
}

练习19.9

class Base
{
    friend bool operator==(const Base&, const Base&);
public:
    Base() = default;
    Base(int i_) : i(i_) { }
protected:
    virtual bool equal(const Base&) const;
private:
    int i;
};

class Derived : public Base
{
public:
    Derived() = default;
    Derived(std::string s_, int i_) : s(s_), Base(i_) { }
protected:
    bool equal(const Base&) const;
private:
    std::string s;
};

bool operator==(const Base& lhs, const Base& rhs)
{
    return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);
}

bool Base::equal(const Base& rhs) const
{
    return this->i == rhs.i;
}

bool Derived::equal(const Base& rhs) const
{
    auto r = dynamic_cast<const Derived&>(rhs);
    return (this->s == r.s) && this->Base::equal(rhs);
}

int main(int argc, char const* argv[])
{
    int arr[10];
    Derived d;
    Base* p = &d;
    std::cout << typeid(42).name() << ", "
        << typeid(arr).name() << ", "
        << typeid(Sales_data).name() << ", "
        << typeid(std::string).name() << ", "
        << typeid(p).name() << ", "
        << typeid(*p).name() << std::endl;
}

int, int [10], class Derived, class Sales_data, class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >, class Base *, class Derived

练习19.10

(a)class A *

(b)class A *

(c)class B

练习19.11

普通的数据指针指向一个对象;类成员指针指向类的非静态成员。当初始化这样一个指针时,我们令其指向类的某个成员,但是不指定该成员所属的对象;直到使用成员指针时,才提供所属的对象。

练习19.12

static const pos Screen::* pcursor() { return &Screen::cursor; }

练习19.13

static const string Sales_data::* pbookNo() { return &Sales_data::bookNo; }

练习19.14

合法,传入参数和返回类型都相同

练习19.15

普通函数指针和指向成员函数的指针区别在于不存在自动转换规则

练习19.16

using Action = double(Sales_data::*)()const;

练习19.17

template<pos X, pos Y>
class Screen {
public:
    friend class Window_mgr;
    friend std::istream& operator>>(std::istream& is, Screen<X, Y>& s){
        char a;
        is >> a;
        std::string temp(X* Y, a);
        s.contents = temp;
        return is;
    }
    friend std::ostream& operator<<(std::ostream& os, Screen<X, Y>& s){
        unsigned int i, j;
        for (i = 0; i < s.height; i++)
        {
            os << s.contents.substr(0, X) << std::endl;
        }
        return os;
    }
    //Screen(pos ht,pos wd):height(ht),width(wd),contents(ht*wd,' '){}
    using Action = Screen<X, Y>&(Screen<X, Y>::*)(char);
    using Action = Screen<X, Y>&(Screen<X, Y>::*)(pos, pos, char);
    using Action = Screen<X, Y>& (Screen<X, Y>::*)(pos, pos);
    using Action = Screen<X, Y>& (Screen<X, Y>::*)(std::ostream& os)const;
    Screen<X, Y>(char c=' ') :height(X), width(Y), contents(height* width, c) {}
    static const pos Screen::* pcursor() { return &Screen::cursor; }
    static const std::string Screen::* data() { return &Screen::contents; }
    Screen<X, Y>& set(char);
    Screen<X, Y>& set(pos, pos,char);
    Screen<X, Y>& move(pos, pos);
    Screen<X, Y> display(std::ostream& os);
    const Screen<X, Y> display(std::ostream& os)const;
    pos size() const; 
private:
    pos cursor = 0;
    pos height = 0, width = 0;
    std::string contents;
    void do_display(std::ostream& os)const {
        os << contents;
    }
};

练习19.18

int main(int argc, char* argv[]) {
    vector<string>vec_str{"","",""};
    cout<<std::count_if(vec_str.begin(), vec_str.end(), std::mem_fn(&string::empty));
}

练习19.19

int main(int argc, char* argv[]) {
    vector<Sales_data>vec_str;
    Sales_data record;
    double fee;
    cin >> fee;
    while (cin >> record) {
        vec_str.push_back(record);
    }
    auto f = std::mem_fn(&Sales_data::avg_price);
    std::find_if(vec_str.begin(), vec_str.end(),[&](Sales_data& s) {return f(s)>fee; });
}

练习19.20

#include <fstream>
using std::ifstream;
using std::ofstream;
#include <iostream>
using std::cin;
using std::cout;
using std::endl;
#include <map>
using std::map;
using std::multimap;
#include <set>
using std::multiset;
using std::set;
#include <sstream>
using std::istringstream;
#include <string>
using std::string;
#include <unordered_map>
using std::unordered_map;
#include <vector>
#include "StrVec.h"
#include <algorithm>
using std::vector;
#ifndef TEXTQUERT_H_
#define TEXTQUERT_H_
#include "DebugDelete.h"
namespace chapter10 {
   
    class TextQuery
    {
        friend class QueryResult;
    public:
        class QueryResult;
        TextQuery() :text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>")) {}
        TextQuery(ifstream& ifs);
        QueryResult query(string s) const;
        ~TextQuery();

    private:
        std::shared_ptr <StrVec> text;
        std::shared_ptr<map<string, std::shared_ptr<set<size_t>>>> query_words;
    };

    class TextQuery::QueryResult
    {
    public:
        friend std::ostream& print(std::ostream& os, const QueryResult qr);
        using QueryIterator = set<size_t>::iterator;
    public:
        QueryResult(string& w, std::shared_ptr<set<size_t>> n, std::shared_ptr<StrVec> i) :word(w), nos(new set<size_t>, DebugDelete("QueryResult::set<size_t>")), inputs(new StrVec, DebugDelete("QueryResult::StrVec")) {
            nos = n;
            inputs = i;
        }
        ~QueryResult();
        QueryIterator begin() { return nos->begin(); }
        QueryIterator end() { return nos->end(); }
        std::shared_ptr <StrVec> get_file() { return inputs; }
    private:
        string word;
        std::shared_ptr<set<size_t>> nos;
        std::shared_ptr<StrVec> inputs;
    };

    TextQuery::QueryResult::~QueryResult()
    {
    }

    inline TextQuery::TextQuery(ifstream& ifs) : text(new StrVec, DebugDelete("TextQuery::StrVec")), query_words(new map<string, std::shared_ptr<set<size_t>>>, DebugDelete("TextQuery::map<string, std::shared_ptr<set<size_t>>>"))
    {
        size_t size = 0;
        if (ifs) {
            for (string line; getline(ifs, line, '.'); ++size)
            {
                text->push_back(line);
                istringstream iss(line);
                size = text->size();
                for (string text, word; iss >> text; word.clear()) {
                    std::remove_copy_if(text.begin(), text.end(),
                        std::back_inserter(word), ispunct);
                    // use reference avoid count of shared_ptr add.
                    auto& nos = (*query_words)[word];
                    if (!nos) nos.reset(new std::set<size_t>);
                    nos->insert(size);
                }
            }
        }
    }

    inline TextQuery::QueryResult TextQuery::query(string s) const {
        static std::shared_ptr<std::set<size_t>> nodate(new std::set<size_t>, DebugDelete("TextQuery::std::set<size_t>"));
        auto found = query_words->find(s);
        if (found == query_words->end()) {
            cout << s + " is not in the text" << endl;
            return QueryResult(s, nodate, text);
        }
        else
            return QueryResult(s, found->second, text);
    }
    TextQuery::~TextQuery()
    {
    }

    std::ostream& print(std::ostream& os, const TextQuery::QueryResult qr) {
        os << qr.word << " occurs " << qr.nos->size() << " times" << endl;
        for (auto i : *qr.nos) {
            os << "	(line " << i + 1 << ") " << qr.inputs->at(i) << std::endl;
        }
        return os;
    }
}
#endif // !TEXTQUERT_H_

练习19.21

#include <string>
#ifndef _TOKEN_H_
#define _TOKEN_H_
class Token
{
public:
    Token():tok(INT),ival(0){}
    Token(const Token& t) :tok(t.tok) { copyUnion(t); }
    Token& operator=(const Token&);
    ~Token() { if (tok == STR)sval.~basic_string(); }
    Token& operator=(const std::string&);
    Token& operator=(char);
    Token& operator=(int);
    Token& operator=(double);
private:
    enum 
    {
        INT, CHAR, DBL, STR
    }tok;
    union 
    {
        char cval;
        int ival;
        double dval;
        std::string sval;
    };
    void copyUnion(const Token&);
};

inline Token& Token::operator=(const Token&t)
{
    if (tok == STR && t.tok != STR)sval.~basic_string();
    if (tok == STR && t.tok == STR)
        sval = t.sval;
    else
    {
        copyUnion(t);
    }
    tok = t.tok;
    return*this;
}
inline Token& Token::operator=(const std::string&s)
{
    if (tok == STR)sval = s;
    else
        new (&sval)std::string(s);
    tok = STR;
    return*this;
}
inline Token& Token::operator=(char c)
{
    if (tok == STR)sval.~basic_string();
    cval = c;
    tok = CHAR;
    return*this;
}
inline Token& Token::operator=(int i)
{
    if (tok == STR)sval.~basic_string();
    ival = i;
    tok = INT;
    return*this;
}
inline Token& Token::operator=(double d)
{
    if (tok == STR)sval.~basic_string();
    dval = d;
    tok = DBL;
    return*this;
}
inline void Token::copyUnion(const Token&t)
{
    switch (t.tok)
    {
    case Token::INT:ival = t.ival; break;
    case Token::CHAR:cval = t.cval; break;
    case Token::DBL:dval = t.dval; break;
    case Token::STR: new(&sval)std::string(t.sval); break;
    }
}
#endif // !_TOKEN_H_

练习19.22

#include <string>
#include"Sales_data.h"
#ifndef _TOKEN_H_
#define _TOKEN_H_
class Token
{
public:
    Token():tok(INT),ival(0){}
    Token(const Token& t) :tok(t.tok) { copyUnion(t); }
    Token& operator=(const Token&);
    ~Token() { if (tok == STR)sval.~basic_string(); }
    Token& operator=(const std::string&);
    Token& operator=(const Sales_data&);
    Token& operator=(char);
    Token& operator=(int);
    Token& operator=(double);
private:
    enum 
    {
        INT, CHAR, DBL, STR,SDATA
    }tok;
    union 
    {
        char cval;
        int ival;
        double dval;
        std::string sval;
        Sales_data sdval;
    };
    void copyUnion(const Token&);
};

inline Token& Token::operator=(const Token&t)
{
    if (tok == STR && t.tok != STR)sval.~basic_string();
    if (tok == SDATA && t.tok != SDATA)sdval.~Sales_data();
    if (tok == STR && t.tok == STR)
        sval = t.sval;
    else if (tok == SDATA && t.tok == SDATA)
        sdval = t.sdval;
    else
    {
        copyUnion(t);
    }
    tok = t.tok;
    return*this;
}
inline Token& Token::operator=(const std::string&s)
{
    if (tok == SDATA)sdval.~Sales_data();
    if (tok == STR)sval = s;
    else
        new (&sval)std::string(s);
    tok = STR;
    return*this;
}
inline Token& Token::operator=(const Sales_data& s_data)
{
    if (tok == STR)sval.~basic_string();
    if (tok == SDATA)sdval = s_data;
    else
        new (&sdval)Sales_data(s_data);
    tok = SDATA;
    return*this;
}
inline Token& Token::operator=(char c)
{
    if (tok == STR)sval.~basic_string();
    if (tok == SDATA)sdval.~Sales_data();
    cval = c;
    tok = CHAR;
    return*this;
}
inline Token& Token::operator=(int i)
{
    if (tok == STR)sval.~basic_string();
    if (tok == SDATA)sdval.~Sales_data();
    ival = i;
    tok = INT;
    return*this;
}
inline Token& Token::operator=(double d)
{
    if (tok == STR)sval.~basic_string();
    if (tok == SDATA)sdval.~Sales_data();
    dval = d;
    tok = DBL;
    return*this;
}
inline void Token::copyUnion(const Token&t)
{
    switch (t.tok)
    {
    case Token::INT:ival = t.ival; break;
    case Token::CHAR:cval = t.cval; break;
    case Token::DBL:dval = t.dval; break;
    case Token::STR: new(&sval)std::string(t.sval); break;
    case Token::SDATA: new(&sdval)Sales_data(t.sdval); break;
    }
}
#endif // !_TOKEN_H_

练习19.23

#include <string>
#include"Sales_data.h"
#ifndef _TOKEN_H_
#define _TOKEN_H_
class Token
{
public:
    Token():tok(INT),ival(0){}
    Token(const Token& t) :tok(t.tok) { copyUnion(t); }
    Token& operator=(const Token&);
    Token(Token&& t) :tok(std::move(t.tok)) { moveUnion(std::move(t)); }
    Token& operator=(Token&&);
    ~Token() { if (tok == STR)sval.~basic_string(); }
    Token& operator=(const std::string&);
    Token& operator=(const Sales_data&);
    Token& operator=(char);
    Token& operator=(int);
    Token& operator=(double);
private:
    enum 
    {
        INT, CHAR, DBL, STR,SDATA
    }tok;
    union 
    {
        char cval;
        int ival;
        double dval;
        std::string sval;
        Sales_data sdval;
    };
    void copyUnion(const Token&);
    void moveUnion(const Token&&);
    void free() {
        if (tok == STR)
            sval.std::string::~string();
        if (tok == SDATA)
            sdval.~Sales_data();
    }
};

inline Token& Token::operator=(const Token&t)
{
    if (tok == STR && t.tok != STR)sval.std::string::~string();
    if (tok == SDATA && t.tok != SDATA)sdval.~Sales_data();
    if (tok == STR && t.tok == STR)
        sval = t.sval;
    else if (tok == SDATA && t.tok == SDATA)
        sdval = t.sdval;
    else
    {
        copyUnion(t);
    }
    tok = t.tok;
    return*this;
}
inline Token& Token::operator=(Token&& t)
{
    if (this != &t) {
        free();
        moveUnion(std::move(t));
        std::move(t.tok);
    }
    return *this;
}
inline Token& Token::operator=(const std::string&s)
{
    if (tok == SDATA)sdval.~Sales_data();
    if (tok == STR)sval = s;
    else
        new (&sval)std::string(s);
    tok = STR;
    return*this;
}
inline Token& Token::operator=(const Sales_data& s_data)
{
    if (tok == STR)sval.~basic_string();
    if (tok == SDATA)sdval = s_data;
    else
        new (&sdval)Sales_data(s_data);
    tok = SDATA;
    return*this;
}
inline Token& Token::operator=(char c)
{
    free();
    cval = c;
    tok = CHAR;
    return*this;
}
inline Token& Token::operator=(int i)
{
    free();
    ival = i;
    tok = INT;
    return*this;
}
inline Token& Token::operator=(double d)
{
    free();
    dval = d;
    tok = DBL;
    return*this;
}
inline void Token::copyUnion(const Token&t)
{
    switch (t.tok)
    {
    case Token::INT:ival = t.ival; break;
    case Token::CHAR:cval = t.cval; break;
    case Token::DBL:dval = t.dval; break;
    case Token::STR: new(&sval)std::string(t.sval); break;
    case Token::SDATA: new(&sdval)Sales_data(t.sdval); break;
    }
}
inline void Token::moveUnion(const Token&& t)
{
    switch (t.tok)
    {
    case Token::INT:ival = t.ival; break;
    case Token::CHAR:cval = t.cval; break;
    case Token::DBL:dval = t.dval; break;
    case Token::STR: new(&sval)std::string(std::move(t.sval)); break;
    case Token::SDATA: new(&sdval)Sales_data(std::move(t.sdval)); break;
    }
}
#endif // !_TOKEN_H_

练习19.24

如果是拷贝赋值,则看是否是类类型,则直接赋值,如果是移动赋值则跳过

练习19.25

int main(int argc, char* argv[]) {
    string s = "string";
    Sales_data item("c++ primer 5", 12, 128.0);
    int i = 12;
    char c = 'c';
    double d = 1.28;
    Token t,t1;
    t = i;
    cout << t << "	";
    t1 = t;
    cout << t1 << "	";
    t = d;
    cout << t << "	";
    t = s;
    cout << t << "	";
    t = item;
    cout << t << endl;
    Token t2 = t;
    cout << t2 << "	";
    t2 = s;
    cout << t2 << "	";
    t2 = t;
    cout << t2 << "	";
    t2 = c;
    cout << t2 << "	";
    t = s;
    t2 = std::move(t);
    cout << t2 << endl;
    Token t3 = std::move(t2);
    cout << t3 << "	";
    t3 = t3;
    cout << t3 << "	";
    t3 = item;
    cout << t3 << endl;
    t2 = std::move(t3);
    cout << t2 << endl;

}

练习19.26

不合法,C语言不支持函数重载

原文地址:https://www.cnblogs.com/GodZhuan/p/14141819.html