• C++ PrimerPlus 复习 第八章 函数探幽


    第一章 命令编译链接文件 make文件

    第二章 进入c++

    第三章 处理数据

    第四章 复合类型 (上)

    第四章 复合类型 (下)

    第五章 循环和关系表达式

    第六章 分支语句和逻辑运算符

    第七章 函数——C++的编程模块(上)

    第七章 函数——C++的编程模块(下)

    第八章 函数探幽 内联函数 引用 函数模板

    这章的重点是内联函数,引用,左右值是什么等?
    还有个大重点函数模板,也就是所谓的泛式


    复习后解决下面的问题:
    问:什么情况下编译器可能不会将一个函数处理为内联函数?
    问:内联函数和宏有什么区别?
    问: 引用和指针有什么区别?
    问: 为什么const在函数重载中很重要?
    问: 返回类型是否影响函数重载?
    问:什么是左右值?
    问:函数模板和普通函数有什么不同?
    问:在什么情况下使用显式具体化?

    内联函数;

    总结:

    1. 内联函数是C++为提高程序运行速度所做的一项改进。与常规函数的区别不在于编写方式,而在于C++编译器如何将它们组合到程序中。

    2. 内联函数的编译代码与其他程序代码“内联”起来了。编译器将使用相应的函数代码替换函数调用。对于内联代码,程序无需跳到另一个位置处执行代码,再跳回来。

    3. 使用内联函数可以节省处理函数调用机制的时间,特别是对于执行时间较短的代码段,内联函数可以显著提高效率。

    4. 要使用这项特性,必须在函数声明和定义前加上关键字inline

    5. 程序员请求将函数作为内联函数时,编译器并不一定会满足这种要求。例如当函数过大或函数调用了自己(内联函数不能递归)时。

    6. 尽管程序没有提供独立的原型,但C++原型特性仍在起作用。这是因为在函数首次使用前出现的整个函数定义充当了原型。

    // inline.cpp -- using an inline function
    #include 
    
    // an inline function definition
    inline double square(double x) { return x * x; }
    
    int main()
    {
        using namespace std;
        double a, b;
        double c = 13.0;
    
        a = square(5.0);
        b = square(4.5 + 7.5); // can pass expressions
        cout << "a = " << a << ", b = " << b << "\n";
        cout << "c = " << c;
        cout << ", c squared = " << square(c++) << "\n";
        cout << "Now c = " << c << "\n";
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    点击前往详细问题
    7. 内联功能远远胜过C语言的宏定义。宏是通过文本替换来实现的,并且宏不能按值传递。

    #define SQUARE(X) X*X // 宏定义
    这并不是通过传递参数实现的,而是通过文本替换来实现的——X是“参数”的符号标记。
    
    a = SQUARE(5.0); is replaced by a = 5.0*5.0;
    b = SQUARE(4.5 + 7.5); is replaced by b = 4.5 + 7.5 * 4.5 + 7.5;
    d = SQUARE(c++); is replaced by d = c++*c++;
    上述示例只有第一个能正常工作。可以通过使用括号来进行改进:
    
    #define SQUARE(X) ((X)*(X))
    但仍然存在这样的问题,即宏不能按值传递。即使使用新的定义,SQUARE(C++)仍将c递增两次
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    问题:

    1. 什么是内联函数?

      • 内联函数是C++为提高程序运行速度所做的一项改进,其编译代码与其他程序代码直接结合在一起。对于内联代码,程序无需跳转到另一个位置执行代码再返回。
    2. 如何声明一个内联函数?

      • 在函数声明或定义前加上关键字inline。
    3. 什么情况下编译器可能不会将一个函数处理为内联函数?

      • 当函数过大或函数调用了自己(内联函数不能递归)时,编译器可能不会将其处理成内联函数。
    4. 内联函数和宏有什么区别?

      • 内联函数是通过替换函数调用来实现的,并且可以按值传递参数。而宏是通过文本替换来实现的,并且不能按值传递。

    在这里插入图片描述

    引用变量 (1);

    总结:

    1. C++使用&符号来声明引用。例如,要将rodents作为rats变量的别名,可以这样做:int & rodents = rats; 其中,&不是地址运算符,而是类型标识符的一部分。

    2. 引用的值和地址与其引用的变量完全相同,像一个别名。

    3. 必须在声明引用时将其初始化,不能像指针那样,先声明,再赋值。

    4. 点击前往详细问题 一旦引用被初始化为对某个变量的引用,就不能改变为引用另一个变量。即使试图通过指针改变引用的关联性,也不会成功。
    引用更接近const指针,必须在创建时进行初始化,一旦与某个变量关联起来,就将一直效忠于它。也就是说:

    int & rodents = rats;
    
    • 1

    实际上是下述代码的伪装表示:

    int * const pr = &rats;
    
    • 1

    在这里插入图片描述

    问题:

    1. 什么是C++中的引用?

      • 在C++中,引用是一个已存在变量的别名,具有与原变量相同的值和地址。
    2. 如何声明和初始化引用?

      • 在声明引用时必须进行初始化,例如:int & rodents = rats;
    3. 引用是否可以改变为引用另一个变量?

      • 不可以,一旦引用被初始化为对某个变量的引用,它就不能改变为引用另一个变量。
    4. 引用和指针有什么区别?

      • 主要的区别是,引用必须在声明时进行初始化,并且一旦被初始化后就不能改变为引用另一个变量,它更接近const指针。而指针可以在声明后任何时间进行初始化和改变其指向的对象。

    引用变量 (2);

    总结:

    1. 当函数的参数为引用类型时,函数对其进行的任何修改都会直接反映在原变量上。

    2. 如果不希望函数修改传递给它的信息,同时又想使用引用,则应使用常量引用。如:double refcube(const double &ra);

    3. 在C++中,如果实参与引用参数不匹配,C++将生成临时变量。当前,仅当参数为const引用时,C++才允许这样做。

    4. 应尽可能将引用形参声明为const,这可以避免无意中修改数据的编程错误、使函数能够处理const和非const实参,以及使函数能够正确生成并使用临时变量。

    5. C++11新增了另一种引用——右值引用(rvalue reference)。这种引用可指向右值,是使用&&声明的,主要目的是让库设计人员能够提供有些操作的更有效实现。

    问题:

    1. 函数参数为引用类型时,函数对其进行的修改会如何反映?

      • 函数对引用类型参数的修改会直接反映在原变量上。
    2. 如何防止函数修改传递给它的信息,同时又使用引用?

      • 可以通过使用常量引用来防止函数修改传递给它的信息。例如:double refcube(const double &ra);
    3. 什么情况下C++会生成临时变量?

      • 如果实参与引用参数不匹配,C++将生成临时变量。当前,仅当参数为const引用时,C++才允许这样做。
    4. 为什么应尽可能将引用形参声明为const?

      • 将引用形参声明为const可以避免无意中修改数据的编程错误、使函数能够处理const和非const实参,以及使函数能够正确生成并使用临时变量。
    5. 什么是右值引用?其主要用途是什么?

      • 右值引用是C++11新增的一种引用类型,可以指向右值,使用&&声明。其主要目的是让库设计人员能够提供有些操作的更有效实现。
      • 用途
        这里主要介绍右引用的左右,其实就是直接将右值地址赋值给另外一个对象,相比于值传递(尤其对于临时变量),少了数据的创建和复制,尤其在大数据转移过程中效率看得见。

    左右值

    点击前往详细问题
    左值引用和右值引用
    左值引用:引用一个对象;左值引用在汇编层面其实和普通的指针是一样的;定义引用变量必须初始化,因为引用其实就是一个别名,需要告诉编译器定义的是谁的引用。
    右值引用:就是必须绑定到右值的引用,C++11中右值引用可以实现“移动语义”,通过 && 获得右值引用。
    等号两边必须是左值对应左引用,右值对应右引用。

    int x = 100; // x是左值,100是右值
    int &  y = x;  // 左值引用,y引用x
    
    int & p1 = x * 10;        // 错误,x*6是一个右值
    const int & p2 =  x * 10; // 正确,可以将一个const引用绑定到一个右值
    
    int && p3 = x * 10; // 正确,右值引用
    int && p4 = x;      // 错误,x是一个左值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    如何按引用传递函数参数;

    知识点总结:

    1. 使用引用参数的原因

      • 允许程序员修改调用函数中的数据对象。
      • 通过传递引用而不是整个数据对象,可以提高程序的运行速度,特别是在处理大型结构或类对象时。
    2. 什么时候使用引用、什么时候使用指针、什么时候按值传递

      • 对于使用传递的值而不作修改的函数:
        • 对于小型数据对象,如内置数据类型或小型结构,应按值传递。
        • 对于数组,应使用指针,并将指针声明为指向const的指针,以防止修改。
        • 对于较大的结构,应使用const指针或const引用,以提高效率,避免复制结构所需的时间和空间。
        • 对于类对象,应使用const引用,因为类设计的语义通常要求使用引用,这是C++新增特性的主要原因。
      • 对于修改调用函数中数据的函数:
        • 对于内置数据类型,应使用指针,因为这允许函数修改数据对象。
        • 对于数组,只能使用指针,因为数组名被视为指向数组第一个元素的指针。
        • 对于结构,可以使用引用或指针,具体取决于需要。
        • 对于类对象,应使用引用,因为类对象通常按引用传递以确保操作不复制整个对象。

    问题和答案:

    问题 1: 为什么在处理大型结构或类对象时应使用const引用或const指针?

    答案: 使用const引用或const指针可以提高程序的效率,因为它们避免了复制大型结构或类对象所需的时间和空间开销。这样,函数可以访问对象的内容而不进行复制。

    问题 2: 什么时候应该使用指针而不是引用?

    答案: 指针应该在需要修改数据对象的函数中使用,因为指针允许函数修改数据。对于内置数据类型和数组,通常使用指针。

    问题 3: 为什么在C++中传递类对象参数的标准方式是按引用传递?

    答案: 传递类对象参数按引用传递是C++中的标准方式,因为类设计的语义通常要求使用引用。这确保了在函数中操作类对象时不会复制整个对象,提高了效率。

    问题 4: 为什么对于基本类型如int,cin使用引用,而不是按值传递?

    答案: cin使用引用是为了允许函数修改输入的基本类型数据,而不是传递它们的副本。这使得代码更加清晰,例如,可以使用cin >> n而不是cin >> &n

    默认参数;

    重要知识点总结:

    1. 默认参数是指在函数定义中为参数提供一个默认值,使得在函数调用时可以选择性地省略某些参数,从而提高函数的灵活性。

    2. 默认参数必须在函数原型中指定,并通过赋值来初始化参数的默认值

    3. 默认参数的设置必须从右向左进行,即必须为右边的参数提供默认值,不能仅为左边的参数提供默认值。

    4. 函数调用时,实参按从左到右的顺序依次赋给对应的形参,不能跳过任何参数。

    5. 默认参数并非重大编程突破,但提供了一种便捷的方式,可以减少函数的重载数量,特别在设计类时很有用。

    重要问题和答案:

    问题 1: 什么是默认参数?为什么它们对函数的灵活性有所帮助?

    答案: 默认参数是指在函数定义中为参数提供默认值,允许在函数调用时省略某些参数。这提高了函数的灵活性,使得函数可以有更多的用法,而不必为每种用法都创建一个新的函数重载。

    问题 2: 如何在函数原型中指定默认参数?

    答案: 默认参数通过在函数原型中为参数赋值来指定。例如,int add(int a, int b = 0) 中的b = 0 就是一个默认参数。

    问题 3: 默认参数的设置顺序是什么?为什么必须从右向左进行?

    答案: 默认参数的设置顺序是从右向左的,这意味着必须为右边的参数提供默认值。这是因为在函数调用时,实参会按照从左到右的顺序依次赋给形参,而不能跳过参数。所以,左边的参数可以省略,但右边的参数不能省略。

    问题 4: 为什么默认参数对于函数重载有用?

    答案: 默认参数可以减少函数的重载数量,因为可以为一个函数提供多个默认参数值,从而覆盖不同的用例,而无需创建多个函数重载来处理不同的参数组合。这可以使代码更清晰和简洁。

    函数重载;

    知识点总结:

    1. 函数重载是C++中的一种特性,允许您定义多个同名函数,但它们的参数列表(特征标)必须不同。
    2. 特征标由参数的数量、类型和顺序组成。
    3. 当调用重载函数时,编译器会根据提供的参数来选择匹配的函数。
    4. 如果没有找到与参数匹配的重载函数,编译器将尝试进行标准类型转换以匹配最接近的函数。
    5. const修饰符在函数重载中起着重要的作用,允许区分对const和非const参数的调用。
    6. 返回类型不会影响函数重载,仅特征标(参数列表)不同的函数才能重载。

    重要问题和答案:

    问题 1: 什么是函数重载,为什么它在C++中很有用?

    答案:函数重载是指在同一个作用域内定义多个同名函数,但它们的参数列表必须不同。这使得您可以使用相同的函数名执行多种不同的操作,根据参数的不同选择合适的函数。这提高了代码的可读性和可维护性,同时提供了更灵活的函数调用方式。

    问题 2: 什么是函数特征标,为何它在函数重载中如此重要?

    答案:函数特征标是函数的参数列表,包括参数的数量、类型和顺序。在函数重载中,编译器使用特征标来确定要调用的函数版本。如果两个函数的特征标相同,它们不能同时存在,因此特征标的唯一性是区分不同重载版本的关键。

    问题 3: 如何区分重载函数中的最佳匹配?

    答案:编译器会尝试选择最匹配的重载函数,首先考虑完全匹配参数的函数,然后考虑进行标准类型转换匹配的函数。如果多个函数都有相同级别的匹配,编译器将报告二义性错误,因为无法确定使用哪个函数。

    问题 4: 为什么const在函数重载中很重要?

    答案:const关键字在函数重载中用于区分对const和非const参数的调用。这允许您编写不同行为的函数版本,以适应不同类型的参数。在C++中,const参数是常量,而非const参数是可修改的,因此const关键字帮助编译器确定最合适的函数。
    将非const值赋给const变量是合法的,但反之则是非法的

    问题 5: 返回类型是否影响函数重载?

    答案:不,返回类型不影响函数重载。函数的重载仅与参数列表(特征标)有关。如果两个函数具有不同的特征标,它们可以具有不同的返回类型,这是合法的。但如果特征标相同,则无法通过返回类型来区分它们。

    函数模板;

    引入

    重要重要重要!
    知识点总结:

    1. 函数模板是C++中的一项特性,允许定义通用的函数,使用泛型来处理不同类型的数据。
    2. 函数模板通过将类型作为参数传递给模板来实现,编译器根据参数类型生成具体的函数实现。
    3. 函数模板可以提高代码的重用性和可维护性,避免手动编写多个相似的函数。
    4. 在函数模板中,关键字template用于声明模板,typename(或class)用于指定类型参数,尖括号用于包裹类型参数。
    template <typename AnyType>
    void Swap(AnyType &a, AnyType &b)
    {
        AnyType temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    1. 在C++98之前,使用关键字class来声明模板类型参数也是合法的,但现代代码中更常使用typename
    2. 使用函数模板时,编译器会根据参数类型自动生成具体的函数实现。
    3. 函数模板的定义包括函数模板的原型和实际的函数模板定义。
    4. 头文件通常用于存放函数模板的定义,可以在需要使用模板的文件中包含头文件以使用模板。

    重要问题和答案:
    9. 什么是函数模板?函数模板有什么作用?

    • 函数模板是C++中的通用函数描述,允许处理不同类型的数据。它们通过泛型来定义函数,可以根据传递的参数类型自动生成具体的函数实现。函数模板提高了代码的重用性和可维护性,避免了手动编写多个相似的函数。
    1. 如何定义一个函数模板?
    • 要定义一个函数模板,使用template关键字声明模板,使用typename(或class)指定类型参数,然后使用尖括号包裹类型参数。例如:template void Swap(T &a, T &b);
    1. 为什么需要函数模板?有什么优点?
    • 函数模板的主要优点是提高了代码的灵活性和重用性。它们允许以泛型的方式编写代码,可以处理不同类型的数据,减少了代码的冗余和错误。使用函数模板可以简化代码并提高代码的可维护性。
    1. 函数模板的参数类型如何自动推导?
    • 函数模板的参数类型是根据传递给函数的实际参数类型进行推导的。编译器根据函数调用时传递的参数类型生成相应的函数实现。
    1. 函数模板和普通函数有什么不同?
    • 函数模板是通用的函数描述,可以处理不同类型的数据,而普通函数通常只能处理特定类型的数据。函数模板在编译时根据参数类型生成具体的函数实现,而普通函数的参数类型是固定的。
    1. 如何在程序中使用函数模板?
    • 要在程序中使用函数模板,只需调用模板函数即可,编译器会根据参数类型自动生成相应的函数实现。例如:Swap(i, j); 可以调用函数模板 Swap 来交换两个整数。
    1. 头文件通常用于存放函数模板的定义吗?
    • 是的,通常将函数模板的定义放在头文件中,并在需要使用模板的文件中包含该头文件。这有助于模块化代码并提高代码的可维护性。

    函数模板也是可以重载的

    和函数模板一样
    下面看列子就行

    template <typename T>
    void Swap(T &a, T &b)
    {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    template <typename T>
    void Swap(T a[], T b[], int n)
    {
        T temp;
        for (int i = 0; i < n; i++)
        {
            temp = a[i];
            a[i] = b[i];
            b[i] = temp;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    函数模板具体化。

    知识点总结:

    1. 显式具体化(explicit specialization)是C++中一种用于特殊情况的函数模板定义方式。
    2. 显式具体化允许为特定类型提供特定的函数实现,覆盖了通用模板函数的定义。
    3. 显式具体化通过在函数模板的定义前加上template <>并指定类型来实现,例如:template <> void Swap(job &j1, job &j2);
    4. 显式具体化的定义优先于通用模板函数的定义,因此在特定类型的情况下,编译器将选择使用显式具体化的版本。
    5. 显式具体化可以用于解决特定类型的函数需求,而不影响通用模板函数的行为。

    重要问题和答案:

    1. 什么是显式具体化(explicit specialization)?

      • 显式具体化是一种C++中的函数模板定义方式,允许为特定类型提供特定的函数实现,覆盖通用模板函数的定义。
    2. 为什么需要显式具体化?

      • 显式具体化允许在特定情况下提供自定义的函数实现,而不影响通用模板函数的行为。这在需要为特定类型编写特殊代码的情况下非常有用。
    3. 如何定义显式具体化?

      • 显式具体化的定义以template <>开始,然后指定类型和函数参数,例如:template <> void Swap(job &j1, job &j2);
    4. 显式具体化和通用模板函数的优先级如何?

      • 显式具体化的定义优先于通用模板函数的定义,因此在特定类型的情况下,编译器将选择使用显式具体化的版本。
    5. 在什么情况下使用显式具体化?

      • 显式具体化通常用于解决特定类型的函数需求,例如,当需要为某个特定结构或类型编写特殊的交换函数时。这允许在通用模板函数的基础上提供自定义实现。

    你有一个函数模板

    template <typename T>
    void Swap(T &, T &);
    
    • 1
    • 2

    这是这个函数模板的定义,功能是交换

    template <typename T>
    void Swap(T &a, T &b) // general version
    {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    假设定义了如下结构:

    struct job
    {
          char name[40];
          double salary;
          int floor;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    你怎么使用Swap去完成功能呢?,或许你可以重新定义一个函数,但这是愚蠢的,因为如果我有很多个结构,你难不成重新定义这些函数名吗?我只能说连名字都不想记。
    下面就是我们显式具体化的表演时间
    先使用具体化的原型

    template <> void Swap<job>(job &j1, job &j2);
    
    • 1

    重新定义

    template <> void Swap<job>(job &j1, job &j2) // specialization
    {
        double t1;
        int t2;
        t1 = j1.salary;
        j1.salary = j2.salary;
        j2.salary = t1;
        t2 = j1.floor;
        j1.floor = j2.floor;
        j2.floor = t2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    完整的代码

    // twoswap.cpp -- specialization overrides a template
    #include 
    template <typename T>
    void Swap(T &a, T &b);
    
    struct job
    {
        char name[40];
        double salary;
        int floor;
    };
    
    // explicit specialization
    template <> void Swap<job>(job &j1, job &j2);
    void Show(job &j);
    
    int main()
    {
        using namespace std;
        cout.precision(2);
        cout.setf(ios::fixed, ios::floatfield);
        int i = 10, j = 20;
        cout << "i, j = " << i << ", " << j << ".\n";
        cout << "Using compiler-generated int swapper:\n";
        Swap(i,j); // generates void Swap(int &, int &)
        cout << "Now i, j = " << i << ", " << j << ".\n";
    
        job sue = {"Susan Yaffee", 73000.60, 7};
        job sidney = {"Sidney Taffee", 78060.72, 9};
        cout << "Before job swapping:\n";
        Show(sue);
        Show(sidney);
        Swap(sue, sidney); // uses void Swap(job &, job &)
        cout << "After job swapping:\n";
        Show(sue);
        Show(sidney);
        // cin.get();
        return 0;
    }
    
    template <typename T>
    void Swap(T &a, T &b) // general version
    {
        T temp;
        temp = a;
        a = b;
        b = temp;
    }
    
    // swaps just the salary and floor fields of a job structure
    
    template <> void Swap<job>(job &j1, job &j2) // specialization
    {
        double t1;
        int t2;
        t1 = j1.salary;
        j1.salary = j2.salary;
        j2.salary = t1;
        t2 = j1.floor;
        j1.floor = j2.floor;
        j2.floor = t2;
    }
    
    void Show(job &j)
    {
        using namespace std;
        cout << j.name << ": $" << j.salary
             << " on floor " << j.floor << endl;
    }
    下面是该程序的输出:
    
    i, j = 10, 20.
    Using compiler-generated int swapper:
    Now i, j = 20, 10.
    Before job swapping:
    Susan Yaffee: $73000.60 on floor 7
    Sidney Taffee: $78060.72 on floor 9
    After job swapping:
    Susan Yaffee: $78060.72 on floor 9
    Sidney Taffee: $73000.60 on floor 7
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80

    问题区

    问:什么情况下编译器可能不会将一个函数处理为内联函数?

    • 当函数过大或函数调用了自己(内联函数不能递归)时,编译器可能不会将其处理成内联函数。

    问:内联函数和宏有什么区别?

    • 内联函数是通过替换函数调用来实现的,并且可以按值传递参数。而宏是通过文本替换来实现的,并且不能按值传递。

      点击前往详细答案

    问: 引用和指针有什么区别?

    • 主要的区别是,引用必须在声明时进行初始化,并且一旦被初始化后就不能改变为引用另一个变量,它更接近const指针。而指针可以在声明后任何时间进行初始化和改变其指向的对象。
      点击前往详细答案

    问: 为什么const在函数重载中很重要?

    • 答案:const关键字在函数重载中用于区分对const和非const参数的调用。这允许您编写不同行为的函数版本,以适应不同类型的参数。在C++中,const参数是常量,而非const参数是可修改的,因此const关键字帮助编译器确定最合适的函数。
      将非const值赋给const变量是合法的,但反之则是非法的

    问: 返回类型是否影响函数重载?

    • 答案:不,返回类型不影响函数重载。函数的重载仅与参数列表(特征标)有关。如果两个函数具有不同的特征标,它们可以具有不同的返回类型,这是合法的。但如果特征标相同,则无法通过返回类型来区分它们。

    问:什么是左右值?

    问:函数模板和普通函数有什么不同?

    • 函数模板是C++中的通用函数描述,允许处理不同类型的数据。它们通过泛型来定义函数,可以根据传递的参数类型自动生成具体的函数实现。函数模板提高了代码的重用性和可维护性,避免了手动编写多个相似的函数。
    • 函数模板是通用的函数描述,可以处理不同类型的数据,而普通函数通常只能处理特定类型的数据。函数模板在编译时根据参数类型生成具体的函数实现,而普通函数的参数类型是固定的。

    问:在什么情况下使用显式具体化?

    • 显式具体化通常用于解决特定类型的函数需求,例如,当需要为某个特定结构或类型编写特殊的交换函数时。这允许在通用模板函数的基础上提供自定义实现。
  • 相关阅读:
    【名人】王兴语录
    基于STM32+射频模块设计的导盲杖
    SpringMVC面试题
    猿创征文 第二季| #「笔耕不辍」--生命不息,写作不止#
    基于JAVA时间管理系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    Java学习 --- JVM概述
    平均110万个漏洞被积压,企业漏洞管理状况堪忧
    中国预制菜行业发展形势与前景规划建议报告2022-2028年版
    使用策略模式实现 Spring 分布式和单机限流
    验证流程--验证策略
  • 原文地址:https://blog.csdn.net/L2489754250/article/details/132941389