C++ Primer 中文版(第5版) 习题答案
来源:互联网 发布:食品零售数据 编辑:程序博客网 时间:2024/05/16 05:35
- 第13章 拷贝控制
- 第18章 用于大型程序的工具
- 第19章 特殊工具与技术
第13章 拷贝控制
第18章 用于大型程序的工具
Date: 2017-10-08
练习18.1
(a) range_error; (b) range_error;
改写后,将发生异常且程序中止。因为抛出异常时,当前块中创建的指针对象p会被销毁,而p指向的动态内存尚未被释放,造成内存泄漏。
练习18.2
异常发生后,v调用vector类的析构函数销毁,p指针被销毁但指向的内存不会被释放,输入流对象in调用ifstream类的析构函数销毁。
练习18.3
方案一、智能指针
shared_ptr<int> p(new int[v.size()], [](int *p){ delete[] p; });
方案二、类
class intPtr {private: int *p = nullptr;public: intPtr(size_t n): p(new int[n]) {} ~intPtr() { delete[] p; }};
练习18.4
三个类的顺序反序即可
练习18.5
#include <iostream> #include <cstdlib> using namespace std; int main() { try { // } catch (overflow_error e) { cout << e.what(); abort(); } catch (underflow_error u) { cout << u.what(); abort(); } catch (range_error r) { cout << r.what(); abort(); } catch (runtime_error r) { cout << r.what(); abort(); } // end of one inheritance catch (domain_error d) { cout << d.what(); abort(); } catch (invalid_argument i) { cout << i.what(); abort(); } catch (out_of_range o) { cout << o.what(); abort(); } catch (length_error l) { cout << l.what(); abort(); } catch (logic_error l) { cout << l.what(); abort(); } // end of one inheritance catch (bad_alloc b) { cout << b.what(); abort(); } // end of one inheritance catch (bad_alloc b) { cout << b.what(); abort(); } // end of one inheritance catch (exception e) { cout << e.what(); abort(); } // end of all inheritance return 0; }
练习18.6
(a) throw &exceptionType();
(b) throw int() //任意的
(c) throw int()
练习18.7
修改构造函数为
template<typename T>Blob<T>::Blob() try:data(std::make_shared<std::vector<T>>()) { }catch(std::bad_alloc &e) { std::cerr << e.what() << std::endl;}
练习18.8
自行修改
练习18.9
异常类如下
class out_of_stock: public std::runtime_error {public: explicit out_of_stock(const std::string &s): runtime_error(s) { }};class isbn_mismatch: public std::logic_error {public: explicit isbn_mismatch(const std::string &s): logic_error(s) { } isbn_mismatch(const std::string &s, const std::string &lhs, const std::string &rhs): logic_error(s), left(lhs), right(rhs) { } const std::string left, right;};
重载运算符如下
Sales_data& Sales_data::operator+=(const Sales_data& rhs) { if (isbn() != rhs.isbn()) throw isbn_mismatch("wrong isbn", isbn(), rhs.isbn()); units_sold += rhs.units_sold; revenue += rhs.revenue; return *this;}
练习18.10
不捕获异常将中止程序运行
练习18.11
what函数是捕获异常后用来打印异常信息的。即使真的要求what函数抛出异常,也必须在函数体内捕获该异常并处理。
练习18.12
自行修改
练习18.13
当需要定义全局静态变量或局部静态变量时。
换言之,当需要定义的对象、函数、类类型或其他实体在一个作用域中可见时。
练习18.14
mathLib::MatrixLib::matrixmathLib::MatrixLib::operator*( const mathLib::MatrixLib::matrix&,const mathLib::MatrixLib::matrix&);
练习18.15
using指示一次性注入某个命名空间中的所有名字,using声明只注入某个命名空间中的一个名字。
练习18.16
位置1,using声明:
第二个ival将报错declaration already in scope
,且内部dvar将隐藏外部dvar.
位置2,using声明:
内部dvar将报错declaration already in scope
,且内部ivar将隐藏外部ivar.
位置1,using指示: ++ival
处报错Reference to 'ivar' is ambiguous
,且内部dvar将隐藏外部dvar.
位置2,using指示: ++ival
处报错Reference to 'ivar' is ambiguous
,且内部dvar将隐藏外部dvar.
一个有趣现象是,如果ival在manip()内部声明,则无论using指示位于函数内还是函数外,均不会产生错误。且编译器将选用内部ival的声明。
练习18.17
如上
练习18.18
mem1是string时,会调用string类的swap函数;mem1是int时,会调用std的swap函数。
练习18.19
如果using std::swap(v1.mem1, v2.mem1)
,则只能调用std的swap函数。
练习18.20
候选函数集: void primerLib::compute();
void primerLib:compute(const void*);
void compute(int);
void compute(double, double = 3.4);
void compute(char*, char* = 0);
可行函数集: void primerLib:compute(const void*);
void compute(int);
void compute(double, double = 3.4);
void compute(char*, char* = 0);
最佳匹配: void compute(int);
如果将using声明置于f函数中,
候选函数集: void primerLib::compute();
void primerLib:compute(const void*);
可行函数集: void primerLib:compute(const void*);
最佳匹配: void primerLib:compute(const void*);
练习18.21
(a)无错误;
(b)错误,继承列表不可重复;
(c)无错误
练习18.22
执行顺序:A - B - C - X - Y - Z - MI
练习18.23
均允许
练习18.24
ZooAnimal *pz = new Panda("ying_yang");pz -> print(); // 正确,Panda::print()pz -> cuddle(); // 错误,不属于ZooAnimal的接口pz -> highlight(); // 错误,不属于ZooAnimal的接口delete pz; // 正确,Panda::~Panda()
练习18.25
(a) MI::print()
(b) MI::print()
(c) MI::print()
(d) ~MI(); ~D2(); ~Base2(); D1(); Base1();
(e) ~MI(); ~D2(); ~Base2(); D1(); Base1();
(f) ~MI(); ~D2(); ~Base2(); D1(); Base1();
练习18.26
产生二义性(即使参数列表不同)。修改为 mi.Base1::print(42);
练习18.27
(a) 可见的名字有
Base1: ival, dval, cval, print();
Base2: fval, print();
Derived: dval, print(), sval;
MI: ival, print(), dvec, foo();
foo: dval.
(b) 是
ival: Base1, MI;
dval: Base1, Derived;
print: Base1, Base2, Derived, MI.
(c) 见下
(d) 见下
(e) 见下
void MI::foo(double cval) { int dval; dval = Base1::dval + Deriverd::dval; Base2::fval = dvec.back(); sval[0] = Base1::cval;}
练习18.28
无须访问限定符:Derived1::Bar(char); Derived2::ival;
必须有限定符:Base::bar(int); Base::ival; foo(); cval;
练习18.29
(a) 构造顺序: Class - Base - D1 - D2 - MI - Class - Final
析构顺序:相反
(b) 1个Base, 2个Class
(c) ac错误,bd正确。指向基类的指针或者引用可以直接指向派生类对象。
练习18.30
class Base { protected: int ival; public: Base() :ival(0) {}; Base(const Base &b) { ival = b.ival; } Base(int a) :ival(a) {} }; class D1 :public virtual Base { public: D1() :Base() {} D1(const D1 &b) = default; D1(int a) :Base(a) {} }; class D2 :public virtual Base { public: D2() :Base() {} D2(const D2 &b) = default; D2(int a) :Base(a) {} }; class MI :public D1, public D2 { public: MI() {} MI(const MI &m) :Base(m), D1(m), D2(m) {} MI(int i) :Base(i), D1(i), D2(i) {} }; class Final :public MI { public: Final() {} Final(const Final &f) : Base(f), MI(f) {} Final(int i) : Base(i) {} };
第19章 特殊工具与技术
Date: 2017-10-10
练习19.1
#include <iostream>#include <cstdlib>void *operator new(size_t size) { if (void *mem = malloc(size) return mem; else throw bad_alloc();}void operator delete(void *mem) noexcept { free(mem);}
练习19.2
自行尝试
练习19.3
(b)失败,原因是pb指向的对象不包含C对象。
(c)错误,原因是Ambiguous conversion from derived class ‘D’ to base class ‘A’. 如果将A的后续继承变成虚继承则可以转化。
练习19.4
A *pa = new C;try { C &c = dynamic_cast<C&>(*pa); // do something} catch(std::bad_cast e) { cerr << e.what() << std::endl;}
练习19.5
并非所有情况都可以使用虚函数。当一个指向基类的指针,需要调用派生类自己定义的成员时,需要使用dynamic_cast.
练习19.6
见下
练习19.7
见下
练习19.8
见下
//19.6 Query_base *pb1 = new AndQuery(Query("value1"), Query("value2")); Query_base *pb2 = new OrQuery(Query("value1"), Query("value2")); if (AndQuery *pa1 = dynamic_cast<AndQuery*>(pb1)) { cout << "成功" << endl; } else { cout << "失败" << endl; } if (AndQuery *pa2 = dynamic_cast<AndQuery*>(pb2)) { cout << "成功" << endl; } else { cout << "失败" << endl; } //19.7 try { AndQuery &ra1 = dynamic_cast<AndQuery&>(*pb1); cout << "成功" << endl; } catch (bad_cast e) { cout << e.what() << endl; } try { AndQuery &ra2 = dynamic_cast<AndQuery&>(*pb2); cout << "成功" << endl; } catch (bad_cast e) { cout << e.what() << endl; } //19.8 if (typeid(*pb1) == typeid(*pb2)) cout << "pd1与pd2指向的对象类型相同" << endl; else cout << "pd1与pd2的动态类型不相同" << endl; if (typeid(*pb1) == typeid(AndQuery)) cout << "pd1的动态类型是AndQuery" << endl; else cout << "pd1的动态类型并非是AndQuery" << endl;
练习19.9
自行尝试
练习19.10
(a) class A的指针
(b) class A的指针
(c) class A
练习19.11
普通数据指针:指向某个对象或变量的内存地址
数据成员指针:指向类的成员(不指向类的对象)
练习19.12
class Screen {public: static const pos Screen::*p() { return &Screen::cursor; }};
练习19.13
static const std::string Sales_data::* data() { return &Sales_data::bookNo; }
练习19.14
- C++ Primer 中文版(第5版) 习题答案
- C++Primer 中文版第5版 习题3.4
- C++Primer 中文版第5版 习题3.23
- C++Primer 中文版第5版 习题3.26
- C++Primer 中文版第5版 习题3.31/3.32
- C++primer第5版课后练习习题答案 9.4
- C++primer第5版课后练习习题答案9.5
- C++primer第5版课后练习习题答案9.16
- C++primer第5版课后练习习题答案 9.20
- C++primer第5版课后练习习题答案9.26
- C++primer第5版课后练习习题答案9.28
- C++primer第5版课后练习习题答案9.47
- C++primer第5版课后练习习题答案9.51
- C++primer第5版课后练习习题答案9.52
- C++primer第5版课后练习习题答案7.23
- C++Primer 中文版 第五版 第二章课后习题答案
- C++Primer 中文版 第五版 第三章课后习题答案
- C++Primer 中文版 第五版 第四章课后习题答案
- 【XML】C#中XML文件增删改查简单应用
- 2675-静态数据成员与静态成员函数
- 1. 机器学习基石-When can Machine Learn?
- [Golang学习]Ubuntu搭建Go语言开发环境
- windows 10 下安装weex-toolkit
- C++ Primer 中文版(第5版) 习题答案
- 《Win32多线程程序设计》CRT中的多线程
- IOS ——地图里NSString转为CLLocationDegrees类型
- [lcm] Qualcomm平台的显示屏lcd驱动移植步骤
- LeetCode简易题解--053
- vector set_union() /set_intersection【集合合并/交集】
- [lcm] Qualcomm Android Display Subsystem 架构
- java多线程并发
- centos6.6安装windows字体