• 【C++】《C++ Primer》第六章 知识点总结


    目录

    6.1 函数基础

    静态局部对象 static类型

    编程习惯!

    6.2 参数传递

    编程习惯!

    const实参和形参

    main函数的形参

    数组作为参数

    6.3 返回类型和return语句

    错误的return

    尾置返回类型

    6.4 函数重载

    重载和const形参

    const_cast与重载

    作用域对重载的影响

    6.5 特殊用途

    内联函数inline

    6.7 函数指针

    概念

    写法和用法

    函数自动转为函数指针

    再看decltype

    附:部分习题答案


    6.1 函数基础

    静态局部对象 static类型

    static声明后,变量的生命周期就是:从变量创建到程序结束。

    注:static类型变量默认初始化为0

    编程习惯!

    关于函数的声明和定义:

    小结:函数应该在头文件中声明,在源文件中定义。

    附:声明和定义的区别

    6.2 参数传递

    编程习惯!

    关于引用传递的参数类型:const

    const实参和形参

    函数不会改变的形参如果不是const类型,则会有很多限制!

    • 被误认为这个参数是可以修改的!
    • 极大限制了函数所能接受的实参类型:
    1. void test1(int& a) // 非const
    2. {
    3. cout << a << endl;
    4. }
    5. void test2(const int& a) // 非const
    6. {
    7. cout << a << endl;
    8. }
    9. void test()
    10. {
    11. test1(10); // 错误!因为不能用字面值和非const引用绑定!
    12. test2(10); // 正确!因为test2的参数是const型
    13. const int a = 10;
    14. test1(a); // 错误!因为不能用const变量和非const引用绑定!
    15. test2(a); // 正确!因为都是const
    16. }

    因此,可以发现,如果函数的形参只是int&,那么只有int型的实参才能与之绑定;如果是const int&,那么字面值、int型、const int型都可以与之绑定。

    main函数的形参

    数组作为参数

    两个特性:

    • 不允许拷贝数组 --> 无法值传递,只能引用传递
    • 使用数组的时候,会转为指针 --> 传一个数组,实际上传的是首元素指针

    标准库规范:传递指向首元素和尾元素的指针

    例子:

    1. int &test1(int *a, int index) // 返回引用, 第一个参数是数组首元素的地址
    2. {
    3. return a[index]; // 返回第index个元素的引用
    4. }
    5. void test()
    6. {
    7. int a [] = {1,2,3,4,5};
    8. for (auto i : a)
    9. {
    10. cout << i << " ";
    11. }
    12. cout << endl;
    13. test1(a, 1) = 9; // 传入数组a,但会自动转为a[0]的地址; 因为左边是一个引用,因此可作为左值,因此可以直接赋值
    14. for (auto i : a)
    15. {
    16. cout << i << " ";
    17. }
    18. }

    6.3 返回类型和return语句

    错误的return

    尾置返回类型

    记号:->

    1. string a = "wind";
    2. auto test(int *b) -> decltype(a) // auto的类型,就是根据decltype(a)的返回类型得到
    3. {
    4. return a;
    5. }
    6. int main()
    7. {
    8. int b[] = { 1,2,3,4 };
    9. auto c = test(b);
    10. cout << c;
    11. return 0;
    12. }

    下面三个函数等价:

    1. // 结合decltype,依据模板参数推导返回类型
    2. template<typename ArgType1, typename ArgType2>
    3. auto Func1(ArgType1& a, ArgType2& b) -> decltype(a + b)
    4. {
    5. return (a + b);
    6. }
    7. // 在C++14中可省略箭头返回值部分,直接将函数返回类型设置为auto
    8. template<typename ArgType1, typename ArgType2>
    9. auto Func2(ArgType1& a, ArgType2& b)
    10. {
    11. return (a + b);
    12. }
    13. // 也可以直接将返回类型定义为 decltype(auto)
    14. template<typename ArgType1, typename ArgType2>
    15. decltype(auto) Func3(ArgType1& a, ArgType2& b)
    16. {
    17. return (a + b);
    18. }

    6.4 函数重载

    重载和const形参

    只要记住:只有引用指针作为形参,才可以重载!否则,都不行!

    并且,会根据传入的顶层const类型去选择使用哪个重载函数:

    1. // 正确
    2. void test(int& i)
    3. {
    4. cout << " 1 --- " << i << endl;
    5. }
    6. void test(const int& i)
    7. {
    8. cout << " 2 --- " << i << endl;
    9. }
    10. // 错误
    11. void test1(int i)
    12. {
    13. cout << " 1 --- " << i << endl;
    14. }
    15. void test1(const int i)
    16. {
    17. cout << " 2 --- " << i << endl;
    18. }
    19. int main()
    20. {
    21. const int a = 10;
    22. test(a); // a是const,因此选择void test(const int& i), 输出 2 --- 10
    23. return 0;
    24. }

    const_cast与重载

    const_cast常用在函数重载中!主要作用是:const型和非const型的相互转换。

    使用的初衷:通常不希望修改传入的string,因此形参被返回类型都被定义为const,然而有时候需要返回一个非conststring,因此就需要用const_cast过渡一下。

    1. string &test(const string &s1, const string &s2) // 错误,因为传入是const,返回必须是const
    2. {
    3. return s1.size() > s2.size() ? s1 : s2;
    4. }
    5. 正确:
    6. const string &test(const string &s1, const string &s2)
    7. {...}
    8. int main()
    9. {
    10. string s1 = "wind", s2 = "wind1";
    11. string &s = test1(s1, s2); // 错误,因为test返回的是const,因此必须是const型接收
    12. const string &s = test1(s1, s2); // 正确
    13. cout << s;
    14. return 0;
    15. }

    我们不希望修改s1s2,因此test()要以const类型传入;然而我们希望第13行的s是可以修改的,但又必须用const string去接收,此时就不好办了。因此,要用const_cast过渡一下:

    1. const string &test(const string &s1, const string &s2)
    2. {
    3. return s1.size() > s2.size() ? s1 : s2;
    4. }
    5. string& test1(string& s1, string& s2)
    6. {
    7. auto& r = test(const_cast<const string&>(s1), const_cast<const string&>(s2));
    8. return const_cast(r);
    9. }
    10. int main()
    11. {
    12. string s1 = "wind", s2 = "wind1";
    13. string &s = test1(s1, s2);
    14. cout << s;
    15. return 0;
    16. }

    8行,用先用const_cast把非consts1、s2转为const,调用test(),用一个const string &r去接收,然后再用const_castconstr转为非constr

    作用域对重载的影响

    一句话总结:如果在函数内层作用域中对函数做了重载,那么就会忽略所有函数外的函数重载。

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

    6.5 特殊用途

    内联函数inline

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

    关键字:inline

    定义内联函数:

    调用:

    以上表面,对于较大的函数(比如有一百行),即使声明为inline,但编译器也可能不会当做内联函数使用,不然更费时间。

    注:对于inline函数和constexpr函数,通常把声明和定义放在头文件中,因为这两个函数在程序中需要被多次定义,而这些定义必须一致!

    6.7 函数指针

    概念

    顾名思义,就是指向函数的指针,这个指针可以代替函数来使用。

    写法和用法

    声明:

    类型 (*指针名称)(形参);

    例如:

    1. const string& compare(const string& s1, const string& s2)
    2. {
    3. return s1.size() > s2.size() ? s1 : s2;
    4. }
    5. void test()
    6. {
    7. const string& (*p)(const string& s1, const string& s2);
    8. p = compare;
    9. cout << p << endl << &compare << endl; // 输出相同
    10. string b1 = p("wind", "wind1");
    11. cout << b1 << endl;
    12. }

    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:函数指针可以初始化为0nullptr(因为本质上就是指针,遵循指针的初始化原则)

    注2:重载函数指针时,必须清晰界定选用哪个函数,包括形参和返回类型:

    函数自动转为函数指针

    再看decltype

    decltype只会返回类型,不会做任何数据转换!!因此很多时候需要手动转换!例如:

    函数指针那里:

    1. const string& compare(const string& s1, const string& s2)
    2. {
    3. return s1.size() > s2.size() ? s1 : s2;
    4. }
    5. void test()
    6. {
    7. const string& (*p)(const string& s1, const string& s2);
    8. p1 = compare;
    9. string b1 = p1("wind", "wind1");
    10. cout << b1 << endl;
    11. decltype(compare) *p2 = p1; // 重点在这里
    12. cout << &p2 << endl << &p1 << endl; // 地址不一样,不是同一个指针
    13. string b2 = p2("wind", "wind1");
    14. cout << b2 << endl;
    15. }

    14行,decltype(compare)返回的是一个函数类型,因此需要加上*才能得到指针

    附:部分习题答案

    练习6-10

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. void test1(int* a, int* b)
    7. {
    8. int temp;
    9. temp = *a;
    10. *a = *b;
    11. *b = temp;
    12. }
    13. void test()
    14. {
    15. int a = 10, b = 20;
    16. test1(&a, &b);
    17. cout << a << endl << b << endl;
    18. }
    19. int main()
    20. {
    21. test();
    22. return 0;
    23. }

    练习6-12

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. void test1(int& a, int& b)
    7. {
    8. int temp;
    9. temp = a;
    10. a = b;
    11. b = temp;
    12. }
    13. void test()
    14. {
    15. int a = 10, b = 20;
    16. test1(a, b);
    17. cout << a << endl << b << endl;
    18. }
    19. int main()
    20. {
    21. test();
    22. return 0;
    23. }

    练习6-33

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. // 我的答案 -- 写复杂了
    7. vector<int>::iterator test1(vector<int>v, vector<int>::iterator begin, vector<int>::iterator end)
    8. {
    9. if (begin + 1 == end)
    10. {
    11. cout << *begin << endl;
    12. return begin;
    13. }
    14. cout << *begin << endl;
    15. return test1(v, begin + 1, end);
    16. }
    17. // 参考答案
    18. void print(vector<int>v, int index)
    19. {
    20. int size = v.size();
    21. if (index != size)
    22. {
    23. cout << v[index++] << endl;
    24. print(v, index);
    25. }
    26. }
    27. void test()
    28. {
    29. vector<int>v;
    30. for (int i = 0; i < 10; ++i)
    31. {
    32. v.push_back(i);
    33. }
    34. /// 调用我的答案
    35. //vector::iterator begin = v.begin();
    36. //vector::iterator end = v.end();
    37. //vector::iterator iter = test1(v, begin, end);
    38. /// 调用参考答案
    39. int index = 0;
    40. print(v, index);
    41. }
    42. int main()
    43. {
    44. test();
    45. return 0;
    46. }

    练习6-36

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. // 6.36
    7. string(&func())[10];
    8. // 6.37
    9. // 类型别名
    10. typedef string arrT[10];
    11. using arrT1 = string[10];
    12. arrT& func();
    13. arrT1& func();
    14. // 尾置返回类型
    15. auto func()->string(&)[10];
    16. // decltype关键字
    17. string str[10];
    18. decltype(str)& func();
    19. int main()
    20. {
    21. return 0;
    22. }

    练习6-54

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. void test()
    7. {
    8. // 函数的声明
    9. int func(int, int);
    10. // vector对象的声明
    11. vector< decltype(func)* >v;
    12. }
    13. int main()
    14. {
    15. return 0;
    16. }

    练习6-55和6-56

    1. #include
    2. #define _CRT_SECURE_NO_DEPRECATE
    3. using namespace std;
    4. #include
    5. #include
    6. int func1(int a, int b)
    7. {
    8. return a + b;
    9. }
    10. int func2(int a, int b)
    11. {
    12. return a - b;
    13. }
    14. void test()
    15. {
    16. vector< decltype(func1)* >v;
    17. decltype(func1)* p1 = func1;
    18. decltype(func1)* p2 = func2;
    19. v = { p1, p2 };
    20. for (auto i : v)
    21. {
    22. cout << (*i)(1, 1) << endl;
    23. }
    24. }
    25. int main()
    26. {
    27. test();
    28. return 0;
    29. }

  • 相关阅读:
    js制作动态表单
    MTK MFNR
    C++基本知识(二)---函数重载、引用、内联函数、auto关键字
    Android开发常见问题收集(长期更新)
    CAS和AOuth2的比较
    产品设计如何提升客户体验?
    IT项目经理必备的五种能力
    C++11实现的数据库连接池
    elasticsearch 7.X全部版本的新特性与重大变化
    Sql中having和where的区别
  • 原文地址:https://blog.csdn.net/Wind_2028/article/details/127634633