c++中的引用,默认参数,占位参数

C++中的引用是一种别名机制,主要用于函数参数,避免数据复制,提高效率。引用必须在声明时初始化,不可重新绑定,类似const指针。引用与指针的主要区别包括初始化要求、内存占用、可空性等。此外,C++11引入了右值引用,优化了对右值的操作。默认参数和占位参数也是函数定义的重要方面。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++中新增了一种复合类型---引用变量,引用是已定义的变量的别名。例如,如果将b作为a变量的引用,则可以交替使用rats和rodents来表示该变量。那么这种别名有什么作用呢?引用变量的主要用途是用作函数的形参。通过将引用变量用作参数,函数将使用原始数据,而不是其副本。这样除指针之外,引用也为函数处理大型结构提供了一种非常方便的途径,同时对于设计类来说,引用也是必不可少的。

1、创建引用变量

作用:给变量起别名

创建引用变量的格式

(typename&) type_name
数据类型& 别名 = 原名
typename:引用变量类型
type_name:引用变量名

c和c++中使用&符号来指示变量的地址。c++给&符号赋予了另一个含义,将其用来声明引用。

int rats = 10;

int& rodents = a;

其中&不是地址运算符,而是类型标识符的一部分。

就像声明中的char*指的是指向char的指针一样,int&指得是指向int的引用

上述引用声明rats和rodents互换 ----- 它们指向相同的值和内存单元

对于c语言用户而言,首次接触到引用时可能也会有些困惑,因为指向用户很自然的会想到指针,但它们之间还是有区别的。

int rats = 101;

int& rodents = rats;

int* prats = &rats;

表达式rodents和prats都可以和rats互换,而表达式&rodent和prats都可以同&rats互换。

从这一点来说,引用看上去很像伪装表示的指针(其中,*接触引用运算符被隐式理解)

//firstref.cpp
#include <iostream>
using namespace std;


int main(void)
{

    int rats = 101;
    int& rodents = rats;
    int* prats = &rats;

    cout << "rat:" << rats << "\t" << "&rat:" << &rats << endl;
    cout << "rodents:" << rodents << "\t" << "&rodents:" << &rodents << endl;
    cout << "*prat:" << *prats << "\t" << "&prats:" << &prats << endl;

    return 0;

}

引用和指针除了表示法不同外,还有其他的差别。差别之一是,必须在声明引用时将其初始化,而不能像指针一样,先声明,再赋值

int rat;

int& rodent;

rodent = rat; //error

注意:必须在声明引用变量时进行初始化

引用更接近const指针,必须在创建时进行初始化,一旦于某个变量关联起来,就将一致效忠于它。

int& rodents = rats;

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

int *const pr = &rats;

引用的本质是指针常量

指针常量是指针不可改向,也就是为什么引用不可更改

引用不能反复赋值,可以通过初始化声明来设置引用,但不能通过赋值来赋值来设置

引用和指针的区别

1、引用不占用内存空间,指针占用内存空间

2、引用是原来变量的一个别名,跟原来变量实质使用一个东西,指针是一个变量,存储的是一个地址

3、引用只能是一级,但是指针可以有多级指针(**p)

4、引用在定义的时候必须初始化,指针可以不用初始化

5、引用不能是空,指针可以是空(NULL)

6、引用在被初始化后就不能被修改,但是指针可以修改指向内存空间

7、在使用sizeof()函数后返回值可能不同,sizeof(a)和sizeof(p) 即两个都是用sizeof测量后,引用随数据类型不同返回值不同,但是指针的值不会改变

8、自增以后的值不同:a++相当于val++ p++代表p指向val后面的那个内存空间

9、引用在作为函数参数时,可以不用检查;但是指针在作为函数参数的时候需要检查是否为空

2、将引用用作函数参数

引用经常被i用做函数参数,使得函数中的变量名成为调用程序中的变量的别名。这种传递参数的方法称为按引用传递。按引用传递允许被调用的函数能够访问调用函数中的变量,c++新增的这项特性是对c语言的超越,c语言只能按值传递,按值传递导致被调用函数使用调用程序的值的拷贝,当然,c语言也允许避开按值传递的限制,采用按指针传递方式。

//swaps.cpp
#include <iostream>
using namespace std;

void swap_val(int a,int b)
{
    a = a + b;
    b = a - b;
    a = a - b;

    cout << "swap_val:\ta : " << a << "\t" << "b : " << b << endl; 
}

void swap_ptr(int* a,int* b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;

    cout << "swap_ptr:\ta : " << *a << "\t" << "b : " << *b << endl; 
}

void swap_rats(int& a,int& b)
{
    a = a + b;
    b = a - b;
    a = a - b;

    cout << "swap_rats:\ta : " << a << "\t" << "b : " << b << endl; 
}

int main(void)
{

    int a = 10;
    int b = 20;

    swap_val(a,b);
    cout << "a : " << a << "\t" << "b : " << b << endl; 

    swap_ptr(&a,&b);
    cout << "a : " << a << "\t" << "b : " << b << endl; 

    swap_rats(a,b);
    cout << "a : " << a << "\t" << "b : " << b << endl; 

    return 0;
}

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针修改实参

引用作为函数的返回值:

返回引用的函数实际上时被引用的变量的别名(可作为左值及逆行赋值操作)

返回引用的时最重要的一点是应避免返回函数终止时不再存在的内存单元引用

第一次访问的时候可以访问到,那是因为编译器做了保留,但第二次访问的时候就会报错,因为临时变量存放在栈区,函数运行完之后回收栈区资源,临时变量的内存空间已经被释放,此时再访问已经是非法访问空间,编译器会报错。

3、引用的属性和特别之处

先引入一段代码

//cubes.cpp
#include <iostream>
using namespace std;

double cube_val(double a)
{
    a *= a*a;
    return a;
}

double cube_rats(double& ra)
{
    ra *= ra * ra;
    return ra;
}


int main()
{
    double a = 3.0;
    double a1 = 3.0;
    double& b = a1;
    
    cout << cube_val(a);
    cout << " = cube of " << a << endl;

    cout << cube_rats(b);
    cout << " = cube of " << a1 << endl;

    return 0;
}

cube_rats函数修改了传进去的值,而cube_val并没有。这提醒我们为何通常按按值传递。如果程序员的意图是让函数使用传递给它的信息,而不对这些信息进行修改,同时又想使用引用,则应使用常量引用。

临时变量,引用参数和const

如果实参与引用参数不匹配,c++将生成临时变量。当前,仅当参数为const引用时,c++才允许这样做,但以前不是这样。

首先,什么时候将创建临时变量呢?

如果引用参数是const,则编译器将在下面两种情况下生成临时变量:

1、实参的类型正确,但不是左值

2、实参的类型不正确,但可以转换为正确的类型

左值参数是可被引用的数据对象,例如,变量,数组元素,结构成员,引用和接触引用的指针都是左值。非左值包括字面常量(用引号括起的字符串除外,它们由地址表示)和包含多项的表达式。

常规变量和const变量都可视为左值,因为可通过地址访问它们,但常规变量属于可修改的左值,而const变量属于不可修改的左值

const int& ref = 10;(临时变量)

编译器将代码修改

int temp = 10;

int& ref = &temp; 

如果接收引用参数的函数的意图是修改作为参数传递的变量,则创建临时变量将阻止这种意图的实现。解决方法是,禁止创建临时变量,现在的c++标准正是这样做的。

如果声明将引用指定为const,c++将在必要是生成临时变量。实际上,对于形参为const引用的c++函数,如果实参不匹配,则其行为类似于按值传递,为确保原始数据不被修改,将使用临时变量来存储值。

注意:如果函数调用的参数不是左值或与相应的const引用参数的类型不匹配,则c++将创建类型正确的匿名变量,将函数调用的参数的值传递给该匿名变量,并让参数来引用该变量

应尽可能使用const

将引用参数声明为常量数据的引用的理由由三个:

1、使用const可以避免无意中修改数据的编程错误

2、使用const是函数能够处理const和非const实参,否则将只能接收非const数据

3、使用const引用使函数能够正确生成并使用临时变量

c++11新增了另一种引用 --- 右值引用(rvalue reference),这种引用可指向右值,是使用&&声明的:

double&& rref = std::sqrt(9.0);

double j = 15.00;

double&& jred = 2.0*j+18.5;

新增右值引用的主要目的是,让库设计人员能够提供有些操作的更有效实现。

以前的引用(使用&声明的引用)现在称为左值引用。

4、何时使用引用参数

使用引用参数的主要原因有两个:

1、程序员能够修改调用函数中的数据对象

2、通过传递引用而不是整个数据对象,可以提高程序的运行速度

对于使用传递的值而不作修改的函数

1、如果数据对象很小,如内置数据类型或小型结构,则按值传递

2、如果数据对象是数组,则使用指针,因为是唯一的选择,并将指针声明为指向const的指针

3、如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率,这样可以节省复制结构所需的时间和空间

4、如果数据对象是类对象,则使用const引用,类设计的语义常常要求使用引用 传递类对象参数的标准方式是按引用传递

对于修改调用参数中的数据的函数

1、如果数据对象格式是内置数据类型,则使用指针

2、如果数组对象是数组,则只能使用指针

3、如果数据对象是结构,则使用指针或引用

4、如果数据对象是类对象,则使用引用

5、默认参数

概念:在声明函数的时候可以赋予函数参数默认值。所谓默认值就是在调用时,可以不写某些参数的值,编译器会自动把默认值传递给调用语句中(默认参数指的是当函数调用中省略了实参时自动使用的一个值)

如何使用默认值呢?必须通过函数原型

1、如果函数的声明和定义是分开的,必须在声明的时候设置默认值,不可以在定义的时候设置默认值

2、将变量作引用类型参数的默认值,这时变量必须时已经声明且是全局变量

3、若给某一个参数设置了默认值,那么在参数表中其后所有的参数都必须也设置默认值(如果多参数默认,必须满足从右往左连续默认,不能中间空)

//Default_parameters.cpp
#include <iostream>
using namespace std;

const int& ra = 100;

// void show(int a,int b)
// void show(int a,int b = 200)
void show(int a = 100,int b = 200)
{
    cout << "a:" << a << "\tb:" << b << endl;
}

//变量作引用类型参数的默认值,这时变量必须时已经声明且是全局变量
//void show1(int& a)
void show1(int& a = ra)
{
    cout << "a:" << a << endl;
}

//如果多参数默认,必须满足从右往左连续默认,不能中间空
void show2(int a = 10,int b,int c = 30)
{

}

int main(void)
{
    int a = 10;
    int b = 20;

    // show(a,b);
    // show(a);
    //show();

    //show1(ra);
    show1();

    return 0;
}

 

 

 

 

6、占位参数

占位参数:跟默认参数不同,在函数定义时,形参只写类型,不写形参变量名

语法:
返回值类型 函数名(type) //type --- int char
{
    //占用参数的使用场景比较少,只在运算符重载中可以应用    
    //带占位参数的函数调用时,要传入对应类型的参数值
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值