【温故而知新-02】C++函数参数传递

本文详细介绍了C++中六种参数传递方式:传值参数、指针形参、传引用参数、数组形参、可变形参函数及省略符形参,并通过实例展示了每种方式的特点和适用场景。

一、开篇

在C++中,函数参数的传递有六种不同的情况:

(1)传值参数

(2)指针形参

(3)传引用参数

(4)数组形参

(5)可变形参函数

(6)省略符形参

在实际C++使用中,前四种是经常使用到的参数传递方式,后两种可能使用频次不多,但是在阅读其他项目源码时可能会遇见!

二、参数传递基础知识

  • 函数的参数传递有两个概念:【形参和实参的参数传递】 、【 函数调用过程】。

  • 每次函数调用,都会重新创建函数的形参,并使用传入的实参对形参进行初始化(形参初始化的机理与变量初始化一样)。

  • 重磅一句话:函数形参的类型决定了形参与实参的交互方式。如果形参的类型是引用类型,那么它将绑定到对应的实参上;否则,会将实参的值拷贝后赋值给形参。

总结一下:

1、函数调用需要开销。

2、函数形参的类型决定了函数调用时,形参与实参的交互方式:拷贝赋值or引用绑定。

注:站在函数参数传递方式的角度考虑:拷贝赋值又叫做值传递;引用绑定又叫做引用传递

三、传值参数

​ 当初始化一个非引用类型的变量时,初始值会被拷贝给变量。对变量的改动不会影响初始值,因为此刻存在两份值对象。所以,在函数中对形参所做的所有改动操作都不会影响实参。

四、指针形参

​ 函数调用时,指针的行为与其他非引用类型一样。在执行指针拷贝操作时,拷贝的是指针的值,拷贝后,两个指针是不同的指针。但是,指针允许间接的访问到它所指的对象,所以通过指针可以修改它所指对象的值。

在C语言中,常常使用指针类型的形参访问函数外部的对象。在C++语言中,建议使用引用类型的形参替代指针

五、传引用参数

(5-1)使用引用避免拷贝

拷贝大的类类型对象或者容器对象是比较低效的操作,甚至有些类类型(包括IO类型在内)根本就不支持拷贝操作,此时把此类类型作为函数的参数传递,将会引发错误。因此,当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。

如果在函数中不会改变引用形参的值,最好将其声明为常量引用,这么做是一种比较规范的代码设计。

(5-2)使用引用形参返回额外的参数信息

通常, 一个函数只能返回一个值,但是有时候我们的函数需要同时返回多个值,此时则可以使用引用来返回多个结果。

通过函数引用形参返回多个参数。如下代码示例:

#include <iostream>

class student{
public:
    void getStudentInfo(std::string &name,int &age)
    {
        name = m_name;
        age  = m_age;
    }
    
private:
    std::string m_name = "zhangSan";
    int m_age = 25;
};

int main() {
    student stu_1;
    std::string stu1_name;
    int stu1_age;

    stu_1.getStudentInfo(stu1_name,stu1_age);

    std::cout<<"student1_name:"<<stu1_name<<std::endl;
    std::cout<<"student1_age:"<<stu1_age<<std::endl;
    return 0;
}

六、数组形参

数组作为函数的参数传递时,有两个重要特性:

(1)不允许拷贝数组。

(2)使用数组时,编译器通常会将其转换为指针

不能以值传递的方式传递数组,但是函数形参可以写成类似于数组的形式,如下代码:

void print_info(const int *);

void print_info(const int[]);

void print_info(const int[10]);  //数组的大小对函数调用没有影响

因为传递数组是以指针的方式传递,所以我们在函数中是不知道数组的大小,因此需要函数调用者传递额外的数组大小信息。计算数组的大小有三种方式:
(1)使用标记指定数组长度。
这种方式,必须要求数组有一个结束标记,这种对于字符串非常有用,但是对于全是int类型的数组无效。例如以下代码:

void print_array(char *cp)
{  
  if(cp)
  {
    while(*cp)
    {
      std::cout<<*cp++;
    }
  }
}

(2)使用标准库+数组开始位置和结束位置计算数组大小

例如以下代码:

voit print_array(int *start, int *end)
{
  while(start != end)
  {
    std::cout<< *start++ <<std::endl;
  }
}

对于以上代码,在调用print_array()函数的时候,需要传入一个数组的首元素的指针和一个指向数组尾后元素的指针。

int main()
{
  int num[5] = {1,4,3,2,5};
  
  //调用标准库函数begin和end作为print_array()的实参。
  print_array(begin(num), end(num));
}

end()函数用于返回一个数组尾元素的下一个位置。

(3)显式传递一个表示数组大小的参数

例如以下代码:

void print_array(const int ar[],size_t size)
{
  for(size_t i = 0; i < size ; ++i)
  {
    std::cout << ar[i] << std::endl;
  }
}

在函数中使用数组时必须保证对数组的操作不会越界。

七、可变形参函数

在实际开发中,有时我们不能预测传递给函数的实参个数,且我们希望把这一系列的操作归一到一个函数中,在C++11标准中,提供了两种方法实现这种可变形参个数的函数实现方法:

(7-1)initializer_lit形参

#include <iostream>
using namespace std;

void print_error_msg(initializer_list<string> error_info)
{
    for(auto begin = error_info.begin();begin != error_info.end(); begin++)
    {
        cout<< *begin <<endl;
    }
    cout<< "----------------"<<endl;
}

int main() 
{
    int param_num = 3;
    do{
        if(param_num == 3)
        {
            print_error_msg({"03","error","information"});
        }
        else if(param_num == 2)
        {
            print_error_msg({"02","error"});
        }
        else if(param_num == 1)
        {
            print_error_msg({"01"});
        }

    }while ((param_num--) > 0);

    return 0;
}

结果如下:

initializer_list的使用条件和注意事项:

(1)函数中全部实参的类型完全相同!

(2)initializer_list对象中元素永远是常量值,无法改变initializer_list对象中元素的值。

(7-2)省略符形参

省略符形参是为了给C++程序访问特殊的C代码而设置的,这些代码会使用到C标准库中varargs功能。

例如如下代码:

#include <stdio.h>
#include <stdargs.h>
int sum_ops(int num, ...) {
    va_list valist;

    int ret = 0;

    va_start(valist, num);
    for (int i = 0; i < num; i++) {
        ret += va_arg(valist, int);
    }
    va_end(valist);
    return ret;
}

int main() {
    printf("2+3 = %d\n", sum(2, 2, 3));
    printf("1+2+3+4 =  %d\n", sum(4, 1, 2, 3, 4));
}

省略符形参只能出现在形参列表的最后一个位置,形式有两种:


//这种形式指定了ops函数的部分参数的类型,对应于这些形参的实参将会执行正常的类型检查,
//省略符形参所对应的实参无须类型检查。1void ops(param1,param2,...);

//形参声明后面的逗号是可选的。2void ops(...);

省略符形参应该仅仅用于C和C++通用的类型。需要注意的是:大多数类类型的对象在传递给省略符形参时都无法正确拷贝!!!因此,不能将类类型以省略符形参的方式进行传递。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

iriczhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值