cppPrimer学习18th

cppPrimer学习18th

18.1#

Copy
在下列 throw 语句中异常对象的类型是什么? (a) range_error r("error"); throw r; (b) exception *p = &r; throw *p; a) range_error 的拷贝 b) exception 如果是throw p,那么抛出的是拷贝的指针,该内存在跳出时释放了,是有问题的

18.2#

Copy
当在指定的位置发生了异常时将出现什么情况? void exercise(int *b, int *e) { vector<int> v(b, e); int *p = new int[v.size()]; ifstream in("ints"); //此处发生异常 } p指向的内存得不到释放

18.3#

Copy
要想让上面的代码在发生异常时能正常工作,有两种解决方案。请描述这两种方法并实现它们。 void exercise(int *b, int *e) { vector<int> v(b, e); std::shared_ptr<int> p(new int[v.size()], [](int *p) { delete[] p; }); ifstream in("ints"); //此处发生异常 } 方法2,定义自己的类,实现自动的析构 struct intArray { intArray() : p(nullptr) {} explicit intArray(std::size_t s): p(new int[s]) {} ~intArray() { delete[] p; } //! data meber int *p; }; 使用 intArray p(v.size());

18.4#

Copy
查看图18.1所示的继承体系,说明下面的 try 块有何错误并修改它。 try { // 使用 C++ 标准库 } catch (exception) { // ... } catch (const runtime_error &re) { // ... } catch (overflow_error eobj) { /* ... */ } exception 基类应该放在最下面

18.5#

Copy
// 修改下面的main函数,使其能捕获图18.1所示的任何异常类型: #include <exception> #include <iostream> #include <cstdlib> #include <stdexcept> #include <typeinfo> using namespace std; int main() { try{ //使用C++标准库 }catch(bad_cast &r){ cout << r.what(); abort(); }catch(range_error &r){ cout << r.what(); abort(); }catch(underflow_error &r){ cout << r.what(); abort(); }catch(overflow_error &r){ cout << r.what(); abort(); }catch(runtime_error &r){ cout << r.what(); abort(); }catch(length_error &r){ cout << r.what(); abort(); }catch(out_of_range &r){ cout << r.what(); abort(); }catch(invalid_argument &r){ cout << r.what(); abort(); }catch(domain_error &r){ cout << r.what(); abort(); }catch(logic_error &r){ cout << r.what(); abort(); }catch(bad_alloc &r){ cout << r.what(); abort(); }catch(exception &r){ cout << r.what(); abort(); } return 0; }

18.6#

Copy
已知下面的异常类型和 catch 语句,书写一个 throw 表达式使其创建的异常对象能被这些catch语句捕获: (a) class exceptionType { }; catch(exceptionType *pet) { } (b) catch(...) { } (c) typedef int EXCPTYPE; catch(EXCPTYPE) { } a) exceptionType *pt=xxx; throw pt; b) 都可以 c) throw (int)xx

18.7#

Copy
根据第16章的介绍定义你自己的Blob 和 BlobPtr,注意将构造函数写成函数try语句块。 template <typename T> Blob<T>::Blob()try :data(std::make_shared<vector<T>()>) {} catch(const std::bad_alloc &e){ handle_out_of_memory(e); } template<typename T> Blob<T>::Blob(std::initializer_list<T> il) try :data(make_shared<vector<T>>(il)) {} catch(const std::bad_alloc &e){ handle_out_of_memory(e); } template <typename T> BlobPtr<T>::BlobPtr()try:curr(0){} catch (const std::bad_alloc& e) { handle_out_of_memory(e); } template <typename T> BlobPtr<T>::BlobPtr(Blob<T> &a, size_t sz = 0)try : wptr(a.data), curr(sz) {} catch (const std::bad_alloc& e) { handle_out_of_momory(e); }

18.10#

Copy
程序将会执行terminate

18.11#

Copy
一般我们都会打印 e.what, 如果watch异常,相当于 catch里面嵌套try{}catch

18.13#

Copy
什么时候应该使用未命名的命名空间? 达到static的效果,本文件可见 比如一些typedef等也可以

18.14#

Copy
假设下面的operator*声明的是嵌套的命名空间 mathLib::MatrixLib 的一个成员: namespace mathLib { namespace MatrixLib { class matrix { /* ... */ }; matrix operator* (const matrix &, const matrix &); // ... } } 请问你应该如何在全局作用域中声明该运算符? mathLib::MatrixLib::matrix mathLib::MatrixLib::operator* (const matrix &, const matrix &);

18.15#

Copy
说明 using 指示与 using 声明的区别。 using指示 using namespace xxx; 可能有重名的与原来的命名空间 using 声明 using std::cin;

18.16#

18.17#

Copy
//假定在下面的代码中标记为“位置1”的地方是对命名空间 Exercise中所有成员的using声明,请解释代码的含义。 // 如果这些using声明出现在“位置2”又会怎样呢?将using声明变为using指示,重新回答之前的问题。 // 编译不过去 #include <iostream> using namespace std; namespace Exercise { int ivar = 0; double dvar = 0; const int limit = 1000; } // namespace Exercise int ivar = 0; //位置1 // using Exercise::dvar; // using Exercise::ivar; //1..编译不过去 // using Exercise::limit; // using namespace Exercise; int main(int argc, char const *argv[]) { //位置2 编译不过去 // using Exercise::dvar; // using Exercise::ivar; // using Exercise::limit; //using namespace Exercise; double dvar = 3.1416; int iobj = limit + 1; ++ivar; ++::ivar; std::cout << "ivar= " << ivar << std::endl; std::cout << "::ivar= " << ::ivar << std::endl; std::cout << "iobj= " << iobj << std::endl; while (1) ; return 0; }

18.18#

Copy
已知有下面的 swap 的典型定义,当 mem1 是一个 string 时程序使用 swap 的哪个版本? 如果 mem1 是 int 呢?说明在这两种情况下名字查找的过程。 void swap(T v1, T v2) { using std::swap; swap(v1.mem1, v2.mem1); //交换类型的其他成员 } https://zh.cppreference.com/w/cpp/algorithm/swap 1. mem1是string,应该有特例化的swap 2. 为int 时 调用普通的模版函数

18.19#

Copy
如果对swap的调用形如std::swap(v1.mem1, v2.mem1)将会发生什么情况? 调用 std空间中的swap函数

18.20#

Copy
在下面的代码中,确定哪个函数与compute调用匹配。 列出所有候选函数和可行函数,对于每个可行函数的实参与形参的匹配过程来说,发生了哪种类型转换? namespace primerLib { void compute(); void compute(const void *); } using primerLib::compute; void compute(int); void compute(double, double = 3.4); void compute(char*, char* = 0); void f() { compute(0); } 可能的匹配 void compute(int); // 最佳的匹配 void compute(double, double = 3.4); //int->double void compute(char*, char* = 0); //int->char* primerLib::compute(const void *) //int->const void * 如果将using 放在main中的computer前,应该调用primerLib::compute(const void *) //int->const void *

18.21#

Copy
解释下列声明的含义,在它们当作存在错误吗?如果有,请指出来并说明错误的原因。 (a) class CADVehicle : public CAD, Vehicle { ... }; 公开继承CAD 私有继承Vehicle (b) class DbiList : public List, public List { ... }; 非法duplicate base type 'List' invalid (c) class iostream : public istream, public ostream { ... }; 合法公开继承

18.22#

Copy
// 已知存在如下所示的类的继承体系,其中每个类都定义了一个默认构造函数: // class A { ... }; // class B : public A { ... }; // class C : public B { ... }; // class X { ... }; // class Y { ... }; // class Z : public X, public Y { ... }; // class MI : public C, public Z { ... }; // 对于下面的定义来说,构造函数的执行顺序是怎样的? // MI mi; //A, B, C X, Y, Z, MI

18.23#

Copy
使用练习18.22的继承体系以及下面定义的类 D,同时假定每个类都定义了默认构造函数, 请问下面的哪些类型转换是不被允许的? class D : public X, public C { ... }; D *pd = new D; (a) X *px = pd; (b) A *pa = pd; (c) B *pb = pd; (d) C *pc = pd; 都允许,D都是他们的派生类

18.24#

Copy
在第714页,我们使用一个指向 Panda 对象的 Bear 指针进行了一系列调用, 假设我们使用的是一个指向 Panda 对象的 ZooAnimal 指针将会发生什么情况,请对这些调用语句逐一进行说明。

Copy
ZooAnimal *p=new Panda(); pe->print() 正确; Panda::print pe->highlight() 错误; pe->toes() 错误; pe->duddle() 错误; delete pe 正确。 Panda::~Panda

18.25#

Copy
假设我们有两个基类 Base1 和 Base2,它们各自定义了一个名为 print 的虚成员和一个虚析构函数。 从这两个基类中文名派生出下面的类,它们都重新定义了 print 函数: class D1 : public Base1 { /* ... */}; class D2 : public Base2 { /* ... */}; class MI : public D1, public D2 { /* ... */}; 通过下面的指针,指出在每个调用中分别使用了哪个函数: Base1 *pb1 = new MI; Base2 *pb2 = new MI; D1 *pd1 = new MI; D2 *pd2 = new MI; (a) pb1->print(); MI (b) pd1->print(); MI (c) pd2->print(); MI (d) delete pb2; MI (e) delete pd1; MI (f) delete pd2; MI

18.26#

Copy
已知如上所示的继承体系,下面对print的调用为什么是错误的? 适当修改MI,令其对print的调用可以编译通过并正确执行。 MI mi; mi.print(42); struct MI : public Derived, public Base2{ void print(std::vector<double>){}; void print(int x){ Base1::print(x); }

18.27#

Copy
已知如上所示的继承体系,同时假定为MI添加了一个名为foo的函数: int ival; double dval; void MI::foo(double cval) { int dval; //练习中的问题发生在此处 } (a) 列出在MI::foo中可见的所有名字。 Base1 : ival、dval、cval、print Base2 : fval、print Derived: sval、dval、print; MI ival、dvec、printfoo (b) 是否存在某个可见的名字是继承自多个基类的? dval print ival (c) 将Base1的dval成员与Derived 的dval 成员求和后赋给dval的局部实例。 (d) 将MI::dvec的最后一个元素的值赋给Base2::fval。 (e) 将从Base1继承的cval赋给从Derived继承的sval的第一个字符。 //加上 classname::var即可 dval = Base1::dval + Derived::dval; Base2::fval = dvec.back(); sval.at(0) = Base1::cval;

18.28#

Copy
已知存在如下的继承体系,在 VMI 类的内部哪些继承而来的成员无须前缀限定符就能直接访问? 哪些必须有限定符才能访问?说明你的原因。 struct Base { void bar(int); protected: int ival; }; struct Derived1 : virtual public Base { void bar(char); void foo(char); protected: char cval; }; struct Derived2 : virtual public Base { void foo(int); protected: int ival; char cval; }; class VMI : public Derived1, public Derived2 { }; 直接访问 Derived1::bar 直接派生类有这个成员 Derived2::ival 需要的 Base::bar 被派生类覆盖 Base::ival Derived1::foo 派生类有同名的函数 Derived2::foo

18.29#

Copy
已知有如下所示的类继承关系: class Class { ... }; class Base : public Class { ... }; class D1 : virtual public Base { ... }; class D2 : virtual public Base { ... }; class MI : public D1, public D2 { ... }; class Final : public MI, public Class { ... }; (a) 当作用于一个Final对象时,构造函数和析构函数的执行次序分别是什么? Class Base D1 D2 Mi class Final (b) 在一个Final对象中有几个Base部分?几个Class部分? 一个Base 两个class (c) 下面的哪些赋值运算符将造成编译错误? Base *pb; Class *pc; MI *pmi; D2 *pd2; (a) pb = new Class; 非法,使用派生类指针指向基类 (b) pc = new Final; 非法,里面有两个class error: 'Class' is an ambiguous base of 'Final' (c) pmi = pb; 派生=基类 非法 (d) pd2 = pmi; 基类=派生 合法

代码

Copy
class Class { }; class Base : public Class { }; class D1 : virtual public Base { }; class D2 : virtual public Base { }; class MI : public D1, public D2 { }; class Final : public MI, public Class //warning: direct base 'Class' inaccessible in 'Final' due to ambiguity // 因为这里有两个class { }; int main(int argc, const char **argv) { Base *pb; Class *pc; MI *pmi; D2 *pd2; pc = new Final; //error: 'Class' is an ambiguous base of 'Final' return 0; }

18.30#

Copy
// 18.30 在Base中定义一个默认构造函数、一个拷贝构造函数和一个接受int形参的构造函数。 // 在每个派生类中分别定义这三种构造函数,每个构造函数应该使用它的形参初始化其Base部分。 #include <iostream> using namespace std; class Class { public: Class() { cout << "class()" << endl; } }; class Base : public Class { public: // Base() = default; Base() { cout << "Base()" << endl; } Base(int) { cout << "Base(int)" << endl; } Base(const Base &b) {} }; class D1 : virtual public Base { public: D1() = default; D1(int i) : Base(i) { cout << "D1(int)" << endl; } D1(const D1 &d) {} }; class D2 : virtual public Base { public: D2() = default; D2(int i) : Base(i) { cout << "D2(int)" << endl; } D2(const D2 &d) {} }; class MI : public D1, public D2 { public: MI() = default; MI(int i) : D1(i), D2(i) { cout << "MI(int)" << endl; } MI(const MI &m) {} }; class Final : public MI, public Class { public: Final() = default; // Final(int i) : MI(i) { cout << "Final(int)" << endl; } Final(int i) : MI(i), Base(i) { cout << "Final(int)" << endl; } Final(const Final &f) {} }; int main(int argc, char const *argv[]) { Final f(1); // class() // Base(int) // D1(int) // D2(int) // MI(int) // class() // Final(int) while (1) ; return 0; }
posted @   zongzi10010  阅读(264)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示
CONTENTS