目录
static类型用static声明后,变量的生命周期就是:从变量创建到程序结束。
注:static类型变量默认初始化为0
关于函数的声明和定义:

小结:函数应该在头文件中声明,在源文件中定义。
附:声明和定义的区别

关于引用传递的参数类型:const型
![]()
const实参和形参函数不会改变的形参如果不是const类型,则会有很多限制!
- void test1(int& a) // 非const
- {
- cout << a << endl;
- }
-
- void test2(const int& a) // 非const
- {
- cout << a << endl;
- }
-
- void test()
- {
- test1(10); // 错误!因为不能用字面值和非const引用绑定!
- test2(10); // 正确!因为test2的参数是const型
-
- const int a = 10;
- test1(a); // 错误!因为不能用const变量和非const引用绑定!
- test2(a); // 正确!因为都是const
-
- }
因此,可以发现,如果函数的形参只是int&,那么只有int型的实参才能与之绑定;如果是const int&,那么字面值、int型、const int型都可以与之绑定。
main函数的形参
两个特性:
标准库规范:传递指向首元素和尾元素的指针

例子:
- int &test1(int *a, int index) // 返回引用, 第一个参数是数组首元素的地址
- {
- return a[index]; // 返回第index个元素的引用
- }
-
- void test()
- {
- int a [] = {1,2,3,4,5};
-
- for (auto i : a)
- {
- cout << i << " ";
- }
- cout << endl;
-
- test1(a, 1) = 9; // 传入数组a,但会自动转为a[0]的地址; 因为左边是一个引用,因此可作为左值,因此可以直接赋值
- for (auto i : a)
- {
- cout << i << " ";
- }
- }
return
记号:->

- string a = "wind";
-
- auto test(int *b) -> decltype(a) // auto的类型,就是根据decltype(a)的返回类型得到
- {
- return a;
- }
-
- int main()
- {
- int b[] = { 1,2,3,4 };
- auto c = test(b);
- cout << c;
-
- return 0;
- }
下面三个函数等价:
- // 结合decltype,依据模板参数推导返回类型
- template<typename ArgType1, typename ArgType2>
- auto Func1(ArgType1& a, ArgType2& b) -> decltype(a + b)
- {
- return (a + b);
- }
-
- // 在C++14中可省略箭头返回值部分,直接将函数返回类型设置为auto
- template<typename ArgType1, typename ArgType2>
- auto Func2(ArgType1& a, ArgType2& b)
- {
- return (a + b);
- }
-
- // 也可以直接将返回类型定义为 decltype(auto)
- template<typename ArgType1, typename ArgType2>
- decltype(auto) Func3(ArgType1& a, ArgType2& b)
- {
- return (a + b);
- }
只要记住:只有引用和指针作为形参,才可以重载!否则,都不行!
并且,会根据传入的顶层const类型去选择使用哪个重载函数:
- // 正确
- void test(int& i)
- {
- cout << " 1 --- " << i << endl;
- }
-
- void test(const int& i)
- {
- cout << " 2 --- " << i << endl;
- }
-
- // 错误
- void test1(int i)
- {
- cout << " 1 --- " << i << endl;
- }
-
- void test1(const int i)
- {
- cout << " 2 --- " << i << endl;
- }
-
- int main()
- {
- const int a = 10;
- test(a); // a是const,因此选择void test(const int& i), 输出 2 --- 10
-
- return 0;
- }
const_cast与重载const_cast常用在函数重载中!主要作用是:const型和非const型的相互转换。
使用的初衷:通常不希望修改传入的string,因此形参被返回类型都被定义为const,然而有时候需要返回一个非const的string,因此就需要用const_cast过渡一下。
- string &test(const string &s1, const string &s2) // 错误,因为传入是const,返回必须是const
- {
- return s1.size() > s2.size() ? s1 : s2;
- }
- 正确:
- const string &test(const string &s1, const string &s2)
- {...}
-
- int main()
- {
- string s1 = "wind", s2 = "wind1";
- string &s = test1(s1, s2); // 错误,因为test返回的是const,因此必须是const型接收
- const string &s = test1(s1, s2); // 正确
- cout << s;
- return 0;
- }
我们不希望修改s1和s2,因此test()要以const类型传入;然而我们希望第13行的s是可以修改的,但又必须用const string去接收,此时就不好办了。因此,要用const_cast过渡一下:
- const string &test(const string &s1, const string &s2)
- {
- return s1.size() > s2.size() ? s1 : s2;
- }
-
- string& test1(string& s1, string& s2)
- {
- auto& r = test(const_cast<const string&>(s1), const_cast<const string&>(s2));
- return const_cast
(r); - }
-
- int main()
- {
- string s1 = "wind", s2 = "wind1";
-
- string &s = test1(s1, s2);
- cout << s;
- return 0;
- }
第8行,用先用const_cast把非const的s1、s2转为const,调用test(),用一个const string &r去接收,然后再用const_cast把const的r转为非const的r。
一句话总结:如果在函数内层作用域中对函数做了重载,那么就会忽略所有函数外的函数重载。

只有把重载函数放在一个作用域中(例如都在函数外或函数内),才不会被忽略:

inline主要作用:很多条件判断语句可以通过写一个小的函数去等价表示,这样更加清晰明了,也便于后期修改;然而函数调用是需要占用一定资源的(运行更慢),因此内联函数就用来解决这个问题。
关键字:inline
定义内联函数:

调用:


以上表面,对于较大的函数(比如有一百行),即使声明为inline,但编译器也可能不会当做内联函数使用,不然更费时间。
注:对于inline函数和constexpr函数,通常把声明和定义放在头文件中,因为这两个函数在程序中需要被多次定义,而这些定义必须一致!
顾名思义,就是指向函数的指针,这个指针可以代替函数来使用。
声明:
类型 (*指针名称)(形参);
例如:
- const string& compare(const string& s1, const string& s2)
- {
- return s1.size() > s2.size() ? s1 : s2;
- }
-
- void test()
- {
- const string& (*p)(const string& s1, const string& s2);
- p = compare;
-
- cout << p << endl << &compare << endl; // 输出相同
-
- string b1 = p("wind", "wind1");
- cout << b1 << endl;
- }
第1行,是一个函数;
第8-9行,就是定义一个函数指针p,指向第1行的函数;
注意:函数指针的返回类型、形参必须和函数定义保持一致
函数: const string& compare(const string& s1, const string& s2)
函数指针: const string& (*p)(const string& s1, const string& s2);
指针指向函数:p = compare;
第13行,使用函数指针p,代替直接调用函数compare()
注1:函数指针可以初始化为0或nullptr(因为本质上就是指针,遵循指针的初始化原则)
注2:重载函数指针时,必须清晰界定选用哪个函数,包括形参和返回类型:


decltypedecltype只会返回类型,不会做任何数据转换!!因此很多时候需要手动转换!例如:
函数指针那里:
- const string& compare(const string& s1, const string& s2)
- {
- return s1.size() > s2.size() ? s1 : s2;
- }
-
- void test()
- {
- const string& (*p)(const string& s1, const string& s2);
- p1 = compare;
-
- string b1 = p1("wind", "wind1");
- cout << b1 << endl;
-
- decltype(compare) *p2 = p1; // 重点在这里
- cout << &p2 << endl << &p1 << endl; // 地址不一样,不是同一个指针
-
- string b2 = p2("wind", "wind1");
- cout << b2 << endl;
- }
第14行,decltype(compare)返回的是一个函数类型,因此需要加上*才能得到指针
练习6-10
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- void test1(int* a, int* b)
- {
- int temp;
- temp = *a;
- *a = *b;
- *b = temp;
- }
-
-
- void test()
- {
- int a = 10, b = 20;
- test1(&a, &b);
- cout << a << endl << b << endl;
-
-
- }
-
-
- int main()
- {
- test();
-
- return 0;
- }
练习6-12
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- void test1(int& a, int& b)
- {
- int temp;
- temp = a;
- a = b;
- b = temp;
- }
-
-
- void test()
- {
- int a = 10, b = 20;
- test1(a, b);
- cout << a << endl << b << endl;
-
-
- }
-
-
- int main()
- {
- test();
-
- return 0;
- }
练习6-33
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- // 我的答案 -- 写复杂了
- vector<int>::iterator test1(vector<int>v, vector<int>::iterator begin, vector<int>::iterator end)
- {
- if (begin + 1 == end)
- {
- cout << *begin << endl;
- return begin;
- }
- cout << *begin << endl;
- return test1(v, begin + 1, end);
-
- }
-
- // 参考答案
- void print(vector<int>v, int index)
- {
- int size = v.size();
- if (index != size)
- {
- cout << v[index++] << endl;
- print(v, index);
- }
- }
-
- void test()
- {
- vector<int>v;
- for (int i = 0; i < 10; ++i)
- {
- v.push_back(i);
- }
-
- /// 调用我的答案
- //vector
::iterator begin = v.begin(); - //vector
::iterator end = v.end(); - //vector
::iterator iter = test1(v, begin, end); -
- /// 调用参考答案
- int index = 0;
- print(v, index);
-
- }
-
- int main()
- {
- test();
-
- return 0;
- }
练习6-36
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- // 6.36
- string(&func())[10];
-
- // 6.37
- // 类型别名
- typedef string arrT[10];
- using arrT1 = string[10];
- arrT& func();
- arrT1& func();
-
- // 尾置返回类型
- auto func()->string(&)[10];
-
- // decltype关键字
- string str[10];
- decltype(str)& func();
-
-
- int main()
- {
- return 0;
- }
练习6-54
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- void test()
- {
- // 函数的声明
- int func(int, int);
-
- // vector对象的声明
- vector< decltype(func)* >v;
-
- }
-
- int main()
- {
- return 0;
- }
练习6-55和6-56
- #include
- #define _CRT_SECURE_NO_DEPRECATE
- using namespace std;
- #include
- #include
-
- int func1(int a, int b)
- {
- return a + b;
- }
-
- int func2(int a, int b)
- {
- return a - b;
- }
-
- void test()
- {
-
- vector< decltype(func1)* >v;
- decltype(func1)* p1 = func1;
- decltype(func1)* p2 = func2;
-
- v = { p1, p2 };
-
- for (auto i : v)
- {
- cout << (*i)(1, 1) << endl;
- }
-
- }
-
- int main()
- {
- test();
-
- return 0;
- }