IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 《C++ Primer》第18章 18.2节习题答案 -> 正文阅读

[C++知识库]《C++ Primer》第18章 18.2节习题答案

《C++ Primer》第18章 用于大型程序的工具

18.2节 命名空间 习题答案

练习18.11:为什么what函数不应该抛出异常?

【出题思路】

深入理解what函数的作用和在异常处理中所处的重要位置。

【解答】

what函数是在catch异常后用于提取异常基本信息的虚函数,what函数是确保不会抛出任何异常的。如果what函数抛出了异常,则会在新产生的异常中由于what函数继续产生异常,将会产生抛出异常的死循环。所以what函数必须确保不抛出异常。

练习18.12:将你为之前各章练习编写的程序放置在各自的命名空间中。也就是说,命名空间chapter15包含Query程序的代码,命名空间chapter10包含TextQuery的代码;使用这种结构重新编译Query代码示例。

【出题思路】

本题练习将不同程序放置在不同的命名空间中。

【解答】

将Query类以及Query_base类层次定义为命名空间chapter15的成员,并相应修改主函数中的代码(使用限定名引用这些类,或者使用相关的using声明)。

练习18.13:什么时候应该使用未命名的命名空间?

【出题思路】

理解未命名的命名空间的作用和意义。

【解答】

通常,当需要声明局部于文件的实体时,可以使用未命名的命名空间,即在文件的最外层作用域中定义未命名的命名空间。

练习18.14:假设下面的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:说明using指示与using声明的区别。

【出题思路】

深入了解using指示和using声明的特点和用处。

【解答】

一个using指示使得特定命名空间中的所有名字都成为可见的;而一个using声明只能引入特定命名空间中的一个成员。

练习18.16:假定在下面的代码中标记为“位置1”的地方是对于命名空间Exercise中所有成员的using声明,请解释代码的含义。如果这些using声明出现在“位置2”又会怎样呢?将using声明变为using指示,重新回答之前的问题。

namespace Exercise {
	int ivar = 0;
	double dvar = 0;
	const int limit = 1000;
}
int ivar = 0;
//位置1
void manip() {
	//位置2
	double dvar = 3.1416;
	int iobj = limit + 1;
	++ivar;
	++::ivar;
}

【出题思路】

理解命名空间的声明和指示在主函数内和主函数外的差别。

【解答】

如果命名空间Exercise的所有成员的using声明放在标记为“位置1”的地方,则Exercise中的成员在全局作用域中可见。using Exercise::ivar;会导致ivar重复定义的编译错误,因为在全局作用域中也定义了一个同名变量(注意,由using声明引起的二义性错误在声明点检测);而manip中的double dvar = 3.1416;声明了一个局部变量dvar,在函数体作用域中它将屏蔽Exercise::dvar; int iobj = limit + 1;声明了一个局部变量iobj,并用Exercise::limit加1的结果对其进行初始化。

如果命名空间Exercise的所有成员的using声明放在标记为“位置2”的地方,则manip中的double dvar = 3.1416;属于对变量dvar的重复定义,会出现编译错误;int iobj = limit + 1;声明了一个局部变量iobj,并用Exercise::limit加1的结果对其进行初始化;++ivar;访问到的是Exercise::ivar,而++::ivar访问的是全局变量ivar。

如果命名空间Exercise的using指示放在标记为“位置1”的地方,则manip中的double dvar = 3.1416;声明了一个局部变量dvar,在函数体作用域中它将屏蔽Exercise::dvar; int iobj = limit + 1;声明了一个局部变量iobj,并用Exercise::limit加1的结果对其进行初始化;++ivar;访问到的是Exercise::ivar,而++::ivar;访问的是全局变量ivar。

如果命名空间Exercise的using指示放在标记为“位置2”的地方,则Exercise的成员看来好像是声明在全局作用域中的一样,manip中的double dvar = 3.1416;声明了一个局部变量dvar,在函数体作用域中它将屏蔽Exercise::dvar;;int iobj =limit + 1;声明了一个局部变量iobj,并用Exercise::limit加1的结果对其进行初始化;++ivar;出现二义性错误,因为编译器无法分辨是访问Exercise::ivar,还是访问全局变量ivar;而++::ivar访问的是全局变量ivar。

练习18.17:实际编写代码检验你对上一题的回答是否正确。

【出题思路】

通过观察代码中相关变量的变化,深入了解命名空间的作用域。

【解答】

一共有4种情况,所以编程时需要编写4个对应的程序。程序一:

程序一:

#include <iostream>

using namespace std;

namespace Exercise
{
    int ivar = 10;
    double dvar = 0;
    const int limit = 1000;
}

int ivar = 20;
//位置1:插入using声明
//using Exercise::ivar;//编译错误ivar重复定义
using Exercise::dvar;
using Exercise::limit;

int main()
{
    //位置2
    double dvar = 3.1416;   //局部dvar
    int iobj = limit + 1;   //Exercise::limit;
    ++ivar;					//二义性
    ++::ivar;               //二义性
    cout << "dvar = " << dvar << endl;
    cout << "iobj = " << iobj << endl;
    cout << "ivar = " << ivar << endl;

    return 0;
}

运行结果:

?

程序二:

#include <iostream>

using namespace std;

namespace Exercise
{
    int ivar = 10;
    double dvar = 0;
    const int limit = 1000;
}

int ivar = 20;
//位置1:插入using声明


int main()
{
    //位置2:插入using声明
    using Exercise::ivar;
    using Exercise::dvar;
    using Exercise::limit;

    //double dvar = 3.1416;   //编译错误ivar重复定义
    int iobj = limit + 1;   //Exercise::limit;
    ++ivar;					//Exercise::ival;
    ++::ivar;               //二义性
    cout << "dvar = " << dvar << endl;
    cout << "iobj = " << iobj << endl;
    cout << "ivar = " << ivar << endl;

    return 0;
}

运行结果:

?

程序三:

#include <iostream>

using namespace std;

namespace Exercise
{
    int ivar = 10;
    double dvar = 0;
    const int limit = 1000;
}

int ivar = 20;
//位置1:插入using声明
using namespace Exercise;

int main()
{
    //位置2

    double dvar = 3.1416;   //Exercise::dvar;
    int iobj = limit + 1;   //Exercise::limit;
    //++ivar;					//二义性
    ++::ivar;               //二义性
    cout << "dvar = " << dvar << endl;
    cout << "iobj = " << iobj << endl;
    cout << "ivar = " << ::ivar << endl;

    return 0;
}

运行结果:

?

程序四:

#include <iostream>

using namespace std;

namespace Exercise
{
    int ivar = 10;
    double dvar = 0;
    const int limit = 1000;
}

int ivar = 20;
//位置1

int main()
{
    //位置2:插入using声明
    using namespace Exercise;

    double dvar = 3.1416;   //Exercise::dvar;
    int iobj = limit + 1;   //Exercise::limit;
    //++ivar;					//二义性
    ++::ivar;               //二义性
    cout << "dvar = " << dvar << endl;
    cout << "iobj = " << iobj << endl;
    cout << "ivar = " << ::ivar << endl;

    return 0;
}

运行结果:

?

练习18.18:已知有下面的swap的典型定义(参与13.3节,第457页),当mem1是一个string时程序使用swap的哪个版本?如果mem1是int呢?说明在这两种情况下名字查找的过程。

void swap(T v1, T v2)
{
	using std::swap;
	swap(v1.mem1, v2.mem1);
	//交换类型T的其他成员
}

【出题思路】

深入理解同一函数在拥有不同类型的参数时名字查找的过程。

【解答】

如果mem1是string类型,编译器除了在常规作用域中查找匹配的swap外,还会查找string所属的命名空间中是否有string类型特定版本的swap函数。但对string而言,找到的就是std::swap,完成两个字符串内容的交换。若mem1是int类型,由于int是内置类型,没有特定版本的swap,只会在常规作用域中查找。由于using声明的作用,最终会调用std::swap,完成两个int的交换。

练习18.19:如果对swap的调用形如std::swap(v1.mem1, v2.mem1)将发生什么情况?

【出题思路】

理解强制调用特定版本的函数时需要如何操作。

【解答】

将直接使用标准库版本的swap,而不会查找特定版本的swap或常规作用域中的其他swap。

练习18.20:在下面的代码中,确定哪个函数与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);
}

如果将using声明置于函数f中compute的调用点之前将发生什么情况?重新回答之前的那些问题。【出题思路】

理解主函数内外using声明和重载的特性。

【解答】

全局作用域中声明的函数void compute(int)与compute函数的调用匹配。

候选函数:命名空间primerLib中声明的两个compute函数(因using声明使得它们在全局作用局中可见),以及全局作用域中声明的三个compute函数。

可行函数:因函数调用中给出的实参0为int型,所以可行函数为以下4个函数:

void compute(int);
void compute(double, double = 3.4;
void compute(char *, char * = 0);
primerLib中声明的void compute(const void*)

其中,第一个为完全匹配,第二个需要将实参隐式转换为double类型,第三个需要将实参隐式转换为char*类型,第四个需要将实参隐式转换为void*类型方可匹配,所以第一个为最佳匹配。

如果将using声明置于函数f中compute的调用点之前,则primerLib中声明的voidcompute(const void*)与compute函数的调用匹配。

候选函数:命名空间primerLib中声明的两个compute函数(因using声明使得它们在函数f的函数体作用域中可见,并屏蔽了全局作用域中的三个compute函数)。

可行函数:因函数调用中给出的实参0为int型,所以可行函数为primerLib中声明的void compute(const void*)。需要将实参隐式转换为void*类型方可匹配。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-11-10 12:12:56  更:2021-11-10 12:14:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:02:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码