第六章:默认实参、内联函数、constexpr函数(三种函数的语言特性)专题

一、默认实参
(1)下面哪个声明是错误的?为什么?

   (a) int ff (int a, int b=0, int c=0);
   (b)char *init(int ht = 24, int wd, char bckgrnd);
   解析:(b)是错误的;考察知识点为:一旦函数的某个形参被赋予了默认值,他后面所有的参数都必须有默认值。

(2)下面调用哪个是合法的?为什么?哪个调用虽然是合法的但是显然程序员的初衷不符?为什么?

char *init(int ht, int wd, char bckgrnd = ' ');
(a) init();    (b)init(24,10);   (c)init(14,'*');
解析:(a):ht需要提供实参
      (b):合法
      (c):合法,但是wd会被赋予*号
      考察知识点:
     	知识点1:函数反复调用的过程中重复出现的形参,这样的值被称为默认实参。该参数在使用过程中可以被用户指定,也可以使用默认数值
      	知识点2:调用含有默认实参的函数时,可以包含该实参,也可以省略该实参。
		知识点3:一旦某个形参被赋予了默认值,其后所有形参都必须有默认值。
		知识点4:顺序很重要!在设计函数时,将默认值的形参放在后面。
		知识点5:在给定的作用域中,一个形参只能被赋予一次默认实参,且局部变量不能作为默认实参。

(3)给make_plural函数的第三个形参赋予默认值实参“s”,利用新版本的函数输出 success 和 failure 的单数和复数形式。

				#include 
				#include
				#include
				using namespace std;
				string make_plural(size_t ctr, const string& word, const string& ending = "s")//此处觉得题目描述有误,应该是第三个形参赋予"s",应为是字符串。
				{
					//size_t表示的是unsigned int
					return (ctr > 1) ? word + ending : word;
				}
				int main(int argc, char *argv[])
				{
					cout << "两单词的单数形式:" << make_plural(1, "success", "es") << "  " << make_plural(1, "failure") << endl;
					cout << "两单词的复数形式:" << make_plural(2, "success", "es") << "  " << make_plural(2, "failure") << endl;
					return 0;//代表执行成功
				}

考察知识点:返回的值用于初始化调用点的一个临时量,该临时量就是函数的调用结果——值是如何被返回的
此题考查默认实参的应用。

二、内联函数constexpr函数
(1)你会把哪个声明和定义放在头文件中?哪个放在源文件中?为什么?

 (a)inline bool eq(const Big Int&,const BigInt&){...}
  (b) void putValue(int *arr, int size);
  解析:(a):放在头文件中,为inline函数
        (b):放在头文件中,即使是普通函数,放在头文件中也是较好的
        考点:知识点1:将函数指定为“内联函数(inline)”,将它在每个调用点上“内联的展开”,
                       该说明只是向编译器发出一个请求,编译器可以选择忽略这个请求。
                      内联的机制用于优化规模较小、流程直接、频繁调用的函数,建议不大于75行。
              知识点2:constexpr函数是指能用于常量表达式的函数:
              函数的返回值类型和所有形参的类型必须是“字面值类型”:算术、引用、指针。并且函数体内有且只有一条return语句。
              知识点3:将较小的操作如比较两个字符串的大小定义为函数,有很多的优点。
              知识点4:inline函数和constexpr函数可以在函数中多次定义,但是通常将其定义在头文件中。

三、调试帮助(assert和NDEBUG)
考察的知识点:
知识点1:预处理宏assert(expr):包含一个表达式,expr为真时,assert什么也不做,expr为假时,输出信息并终止程序。包含在cassert头文件中,通常用于检查不能发生的条件。
知识点2:assert依赖于一个NDEBUG的预处理变量的状态,如果定义了NDEBUG,assert什么也不做,默认状态下NDEBUG是未定义的。编译器也可以预先定义该变量。
知识点3:也可以使用NDEBUG编写自己的条件调试代码,如果NDEBUG未定义,将执行#ifndef到#endif之间的代码,如果定义了NDEBUG,这些代码将被忽略。

				void pp()
				{
				    #ifndef NDEBUG
						cerr<<"my name is:"<<__func__<

四、改写一下(第205页)练习中使用的递归输出vector内容的程序,使其有条件的输出与执行过程相关的信息。例如每次调用时输出vector对象的大小。分别再打开和关闭调试器的情况下编译并执行这个程序。

										#include 
										#include
										#include
										using namespace std;
										void printVec(vector& vec)
										{
										#ifndef NDEBUG
											cout << "vector size: " << vec.size() << endl;
										#endif
											if (!vec.empty())
											{
												auto tmp = vec.back();
												vec.pop_back();
												printVec(vec);
												cout << tmp << " ";
											}
										}
										int main(int argc, char** argv)
										{
											vector vec{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };//c++11特性
											printVec(vec);
											cout << endl;
											return 0;
										}

五、说明下面这个循环的含义,它对assert的使用合理吗?

 string s;
 while(cin >> s && s !=sought){    } //空函数体
 assert(cin);
 解析:不合理,只要有输入,则assert一直为真,无意义。最好用于检查不能发生的条件,比如:
 assert(s == sought);

你可能感兴趣的:(C++Primer学习笔记)