《C++primer(第五版)》学习之路-第六章:函数
来源:互联网 发布:战网获取数据索引 编辑:程序博客网 时间:2024/05/07 12:22
【 声明:版权所有,转载请标明出处,请勿用于商业用途。 联系信箱:libin493073668@sina.com】
6.1 函数基础
1.函数是一个命名了的代码块,我们通过调用函数执行相应的代码。函数可以有0个或者多个参数,而且(通常)会产生一个结果。可以重载,也就是说,同一个名字可以对应几个不同的名字。
2.一个典型的函数定义包括以下部分:返回类型,函数名字,由0个或多个形参组成的列表以及函数体。其中,形参以逗号隔开,形参的列表位于一对圆括号之内。函数执行的操作在语句块中说明,该语句块成为函数体。
3.我们通过调用运算符来执行函数。调用运算符的形式是一对圆括号,它作用于一个表达式,该表达式是函数或者指向函数的指针:圆括号之内是一个用括号给的实参列表,我们用实参初始化函数的形参。调用表达式的类型就是函数的返回类型。
4.名字的作用域是程序文本的一部分,名字在其中可见。
对象的生命周期是程序执行过程中该对象存在的一段时间。
形参和函数体内部定义的变量统称为局部变量。
5.我们把只存在于块执行期间的对象称为自动对象。当块执行结束后,块中创建的自动对象的值就变成未定义的了。
6.局部静态对象在程序的执行路径第一次经过对象定义语句时初始化,并且直到程序终止才被销毁,在此期间即使对象所在的函数结束执行也不会对它有影响。
6.2 参数传递
1.当形参是引用类型时,我们说它对应的实参被引用传递或者函数被传引用调用。
当实参的值被拷贝给形参时,形参和实参是两个相互独立的对象。我们说这样的实参被值传递或者函数被传值调用。
2.如果函数无需改变引用形参的值,最好将其声明为常量引用。
3.initializer_list:
使用时包含头文件:
#include<initializer_list>
initializer_list提供的操作:
initializer_list<T>1st: 默认初始化;T类型元素的空列表
initializer_list<T>1st{a,b,c...}: 1st的元素数量和初始值一样多;1st的元素是对应初始值的副本;列表中的元素是const
1st2(1st): 拷贝或赋值一个initializer_list对象不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素
1st2 = 1st: 同上
1st.size(): 列表中的元素数量
1st.begin(): 返回指向1st中首元素的指针
1st.end(): 返回指向1st中尾元素下一位置的指针
6.3 返回类型和return语句
1.没有返回值的return语句只能用在返回类型时void的函数中。
只要函数的返回类型不是void,则该函数内的每条return语句必须返回一个值。return语句返回值的类型必须与函数的返回类型相同,或者能隐式的转换成函数的返回类型。
2.如果一个函数调用了它自身,不管这种调用时直接的还是间接的,都称该函数为递归函数。
6.4 函数重载
1.如果同一作用域内的几个函数名字相同但形参列表不同,我们称之为重载函数。
不允许两个函数除了返回类型外其他所有的要素都相同。
2.函数匹配是指一个过程,在这个过程中我们把函数调用与一组重载函数中的某一个关联起来,函数匹配也叫做重载确定。
3.调用重载函数时有三种可能的结果:
编译器找到一个与实参最佳匹配的函数,并生成调用该函数的代码。
找不到任何一个函数与调用的实参匹配,此时编译器发出无匹配的错误信息。
有多于一个函数可以匹配,但是每一个都不是最佳选择。此时也将发生错误,称为二义性调用。
6.5 特殊用途语言特性
1.某些函数有这样一种形参,在函数的很多次调用中它们都被赋予一个相同的值,此时,我们把这个反复出现的值称为函数的默认实参。调用含有默认实参的函数时,可以包含该实参,可以省略该实参。
一旦某个形参被赋予了默认值,它后面所有形参都必须有默认值。
2.内联说明只是向编译器发出的一个请求,编译器可以选择忽略这个请求。
一般来说,内联机制用于优化规模较小、流程直接、频繁调用的函数,很多编译器都不支持内联递归函数。
3.constexpr函数是指能用于常量表达式的函数。
函数返回类型及所有形参的类型都得是字面值类型,而且函数体重必须有且只有一条return语句。
4.
_ _func_ _ 输出当前调试的函数的名字
_ _FILE_ _ 存放文件名的字符串字面值
_ _LINE_ _ 存放当前行号的整型字面值
_ _TIME_ _ 存放文件编译时间的字符串字面值
_ _DATE_ _ 存放文件编译日期的字符串字面值
6.6 函数匹配
1.函数匹配的第一步是选定本次调用对应的重载函数集,集合中的函数称为候选函数。候选函数具备两个特征:一是与被调用的函数同名,二是其声明在调用点可见。
第二步考察本次调用提供的实参,然后从候选函数中选出能被这组实参调用的函数,这些新选出的函数称为可行函数。可行函数也有两个特征:一是其形参数量与本次调用提供的实参数量相等,二是每个实参的类型与对应的形参类型相同,或者能转换成形参的类型。
2.为了确定最佳匹配,编译器将实参类型到形参类型的转换划分成几个风机,具体排序如下所示:
a.精确匹配,包括以下情况:
实参类型和形参类型相同
实参从数组类型或函数类型转换成对应的指针类型
向实参添加顶层const或者从实参中删除底层const
b.通过const转换实现的匹配
c.通过类型提升实现匹配
d.通过算术类型转换
e.通过类类型转换实现匹配
6.7 函数指针
1.函数指针指向的是函数而非对象。和其他指针一样,函数指针指向某种特定类型。函数的类型由它的返回类型和形参类型共同决定,与函数名无关。
2.当我们使用重载函数时,上下文必须清晰地界定到底应该选用哪个函数。如果定义了指向重载函数的指针,编译器通过指针类型决定选用哪个函数,指针类型必须与重载函数中的某一个精确匹配。
PS:部分练习答案
练习6.2
(a) string f() { string s; // ... return s; }(b) void f2(int i) { /* ... */ }(c) int calc(int v1, int v2) { /* ... */ }(d) double square (double x) { return x * x; }
练习6.3
#include <iostream>int fact(int val){if (val == 0 || val == 1) return 1;else return val * fact(val-1);}int main(){int j = fact(5);std::cout << "5! is " << j << std::endl;return 0;}
练习6.4
#include <iostream>void factorial(){int num;std::cout << "Please input a positive number: ";while (std::cin >> num && num < 0)std::cout << "Please input a positive number again: ";std::cout << num;unsigned long long result = 1;while (num > 1) result *= num--;std::cout << "! is ";if (result)std::cout << result << std::endl;elsestd::cout << "too big" << std::endl;}int main(){factorial();}
练习6.5
template <typename T>T abs(T i){ return i >= 0 ? i : -i;}
练习6.7
size_t generate(){ static size_t ctr = 0; return ctr++;}
练习6.8
Chapter6.h
int fact(int val);int func();template <typename T> T abs(T i){ return i >= 0 ? i : -i;}
练习6.9
fact.cc
#include "Chapter6.h"#include <iostream>int fact(int val){ if (val == 0 || val == 1) return 1; else return val * fact(val - 1);}int func(){ int n, ret = 1; std::cout << "input a number: "; std::cin >> n; while (n > 1) ret *= n--; return ret;}
factMain.cc
#include "Chapter6.h"#include <iostream>int main(){ std::cout << "5! is " << fact(5) << std::endl; std::cout << func() << std::endl; std::cout << abs(-9.78) << std::endl;}
#include <iostream>#include <string>#include <stdexcept>void swap(int* a, int* b){int tmp;tmp = *a;*a= *b;*b= tmp;}int main(){int a,b;std::cout << "Please Enter:\n";while(std::cin >> a >> b){swap(&a, &b);std::cout << a << " " << b << std::endl;std::cout << "Please Enter:\n";}return 0;}
练习6.11
#include <iostream>void reset(int& i){i = 0;}int main(){int i = 42;reset(i);std::cout << i << std::endl;return 0;}
练习6.12
#include <iostream>#include <string>void swap(int& a, int& b){int temp = a;a = b;b = temp;}int main(){int a,b;std::cout << "Please Enter:\n";while(std::cin >> a >> b){swap(a, b);std::cout << a << " " << b << std::endl;std::cout << "Please Enter:\n";}return 0;}
练习6.17
#include <iostream>#include <string>using std::cout;using std::endl;using std::string;bool hasUppercase(const string& str){for (auto c : str)if (isupper(c)) return true;return false;}void makeLowercase(string& str){for (auto& c : str)if (isupper(c)) c = tolower(c);}int main(){string str("Hello World!");cout << hasUppercase(str) << endl;makeLowercase(str);cout << str << endl;return 0;}
练习6.18
a
bool compare(matrix &m1, matrix &m2){ /.../ }b
vector<int>::iterator change_val(int, vector<int>::iterator) { /.../ }
练习6.21
#include <iostream>using std::cout;int Max(const int i, const int* ip){return (i > *ip) ? i : *ip;}int main(){int c = 6;cout << Max(7, &c);return 0;}
#include <iostream>void swap(int*& l, int*& r){ auto tmp = l; l = r; r = tmp;}int main(){ int i = 42, j = 99; auto l = &i; auto r = &j; swap(l, r); std::cout << *l << " " << *r << std::endl; return 0;}
练习6.23
#include <iostream>using std::cout;using std::endl;using std::begin;using std::end;void print(const int* pi){if (pi) cout << *pi << endl;}void print(const char* p){if (p)while (*p) cout << *p++;cout << endl;}void print(const int* beg, const int* end){while (beg != end) cout << *beg++ << endl;}void print(const int ia[], size_t size){for (size_t i = 0; i != size; ++i){cout << ia[i] << endl;}}void print(int(&arr)[2]){for (auto i : arr) cout << i << endl;}int main(){int i = 0, j[2] = {0, 1};char ch[5] = "pezy";print(ch);print(begin(j), end(j));print(&i);print(j, end(j) - begin(j));print(j);return 0;}
练习6.25 && 6.26
#include <iostream>#include <string>int main(int argc, char** argv){std::string str;for (int i = 1; i != argc; ++i){str += argv[i];str += " ";}std::cout << str << std::endl;return 0;}
练习6.27
#include <iostream>#include <initializer_list>int sum(std::initializer_list<int> il){ int sum = 0; for (auto i : il) sum += i; return sum;}int main(void){ std::cout << sum({1, 2, 3, 4, 5}) << std::endl; return 0;}
练习6.33
#include <iostream>#include <vector>using std::vector;using std::cout;using Iter = vector<int>::iterator;void print(Iter beg, Iter end){if (beg != end){cout << *beg << " ";print(std::next(beg), end);}}int main(){vector<int> vec {1, 2, 3, 4, 5, 6, 7, 8, 9};print(vec.begin(), vec.end());return 0;}
练习6.36
string (&func(string (&arrStr)[10]))[10]
练习6.37
using ArrT = string[10];ArrT& func1(ArrT& arr);auto func2(ArrT& arr) -> string(&)[10];string arrS[10];decltype(arrS)& func3(ArrT& arr);
decltype(arrStr)& arrPtr(int i){return (i % 2) ? odd : even;}
练习6.42
#include <iostream>#include <string>using std::string;using std::cout;using std::endl;string make_plural(size_t ctr, const string& word, const string& ending = "s"){return (ctr > 1) ? word + ending : word;}int main(){cout << "singual: " << make_plural(1, "success", "es") << " " << make_plural(1, "failure") << endl;cout << "plural : " << make_plural(2, "success", "es") << " " << make_plural(2, "failure") << endl;return 0;}
练习6.44
#include <iostream>#include <string>using std::string;inline bool isShorter(const string& s1, const string& s2){return s1.size() < s2.size();}int main(){std::cout << isShorter("pezy", "mooophy") << std::endl;}
练习6.47
#include <iostream>#include <vector>using std::vector;using std::cout;using std::endl;#define NDEBUGvoid printVec(vector<int>& vec){#ifdef NDEBUGcout << "vector size: " << vec.size() << endl;#endifif (!vec.empty()){auto tmp = vec.back();vec.pop_back();printVec(vec);cout << tmp << " ";}}int main(){vector<int> vec {1, 2, 3, 4, 5, 6, 7, 8, 9};printVec(vec);cout << endl;return 0;}
练习6.54
int func(int a, int b);using pFunc1 = decltype(func) *;typedef decltype(func) *pFunc2;using pFunc3 = int (*)(int a, int b);using pFunc4 = int(int a, int b);typedef int(*pFunc5)(int a, int b);using pFunc6 = decltype(func);std::vector<pFunc1> vec1;std::vector<pFunc2> vec2;std::vector<pFunc3> vec3;std::vector<pFunc4*> vec4;std::vector<pFunc5> vec5;std::vector<pFunc6*> vec6;
练习6.55
int add(int a, int b) { return a + b; }int subtract(int a, int b) { return a - b; }int multiply(int a, int b) { return a * b; }int divide(int a, int b) { return b != 0 ? a / b : 0; }
练习6.56
std::vector<decltype(func) *> vec{add, subtract, multiply, divide};for (auto f : vec) std::cout << f(2, 2) << std::endl;
- 《C++primer(第五版)》学习之路-第六章:函数
- C++primer(第五版)第六章函数学习笔记
- 学习c++(c+primer第五版第六章)
- 《C++primer(第五版)》学习之路-第五章:语句
- C++Primer第五版【笔记】——第六章 函数
- C++primer第五版笔记-第六章函数
- C++primer第五版第六章学习笔记
- c++primer第五版第六章练习
- 《C++primer(第五版)》学习之路-第四章:表达式
- 《C++primer(第五版)》学习之路-第七章:类
- c++ primer(第五版)学习笔记及习题答案代码版(第六章)函数
- 《C++primer(第五版)》学习之路-序
- 《C++primer(第五版)》学习之路-第一章:开始
- c++primer第五版课后练习答案(第六章)
- C primer plus(第五版)编程练习第六章
- c++.primer.plus第五版第六章编程练习答案
- C++Primer 中文版 第五版 第六章课后习题答案
- C.Primer.Plus(第六版)第五章编程练习
- sudo源码分析(一)
- 《Android群英传》勘误
- IOS子UITabBarController效果
- lintcode-下一个排列
- Java中的包
- 《C++primer(第五版)》学习之路-第六章:函数
- RANSAC理解
- C++中字符串与数字相互转换
- JavaScript中undefined和is not defined异常
- 【jquery】优化仿淘宝五星评价打分(附注释)
- 【CS学习】——详细设计说明书(机房收费系统)
- hdu 4885
- Mysql 数据库单机多实例部署手记
- hashCode()应该怎么写才能高效?