《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;}


练习6.10

#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;}


练习6.22

#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);


练习6.38

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;


0 0
原创粉丝点击