6.2参数传递

每次调用函数时都会重新创建它的形参

Note:形参初始化的机理和变量初始化一样

 

当形参是引用类型时,它对应的实参被引用传递(passed by reference),引用就是对应实参的别名

当实参的值被拷贝给形参时,形参和实参时两个相互独立的对象。我们说这样的实参被值传递(passed by value)

 

6.2.1传值参数

指针形参

void reset(int *ip)

{

    *ip = 0;//改变指针ip所指对象的值

    ip = 0;  //只改变了ip的局部拷贝,实参未被该改变

}

int main()

{

    int i = 42;

    reset(&i);   //改变i的值而非地址

    cout << "i = " << i <<endl;

    return 0;

}

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

 

6.2.2 传引用参数

void reset(int &i)

{

    i=0;

}

int main()

{

    int j =42;

    reset(j);

    cout << "j = " << j <<endl;

    return 0;

}

使用引用避免拷贝

当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象

bool isShorter(const string & s1 , const string & s2)

    {

        return s1.size()<s2.size();

    }

int main()

{

    const string s1= "a srting ";

    const string s2= "one string";

    //比较两个string对象的长度

    return 0;

}

如果函数无须该百年引用形参的值,最好将其声明为常量引用

 

使用引用形参返回额外信息

如何定义函数使得它能够既返回位置也返回出现次数?

一种方法是定义一个新的数据类型,让它包含位置和数量两个成员

另一种更简单的方法:可以给函数传入一个额外的引用实参,令其保存字符出现的次数:

6.2.3 const形参和实参

形参的顶层const会被忽略

当形参有顶层const时,传给它常量对象或者非常量对象都是可以的,形参的顶层const会被忽略

 void fcn(const int I )

 传入

 void fcn(const int I )//fcn能读取i但是不能向i写值等同于 void fcn(int i)

指针或引用形参与const

可以用非常量初始化一个底层const对象,但是反过来不行

同时一个普通的引用必须用同类型的对象初始化

int main()

{

    int i = 42;   

    const int *cp = &i;  //正确:但是cp不能改变i

    const int &r = i;   //正确:但是r不能改变i

    const int &r2 = 42; //正确

    int *p = cp;        //错误:p和cp类型不一样

    int &r3 = r;        //错误:r3和r的类型不匹配

    int &r4 = 42;       //错误:不能用字面值初始化一个非常量引用

    return 0;

}

同样的规则应用到参数传递上

尽量使用常量引用

定义成普通引会给调用者一种误导,即函数可以修改它的实参的值

此外也会限制函数所能接受的实参类型

6.2.4 数组形参

数组两大性质:不允许拷贝;会转换成指针

因为不能拷贝,所以无法以直传递的方式使用数组参数

因为数组会被转换成指针,所以当我们为函数传递一个数组时,实际上传递的是指向数组首元素的指针

 //尽管形式不同,但这三个print函数是等价的

    //每个函数都有一个const int*的形参

    void print(const *int)

    void print(const int[])   //可以看出来,函数的意图是作用于一个数组

    void print(const int[10]) //这里的维度表示期望数组含有多少个元素,实际不一定

int i = 0 ,j[2] = {0,1};

   print(&i);//正确:&i的类型是int*

   print(j);//正确:j转换成int*并指向j[0]

Warning:和其他使用数组的代码一样,以数组作为形参的函数也必须保证使用数组时不越界

使用标记指定数组的长度

 

管理数组实参的第一种方法是要求数组本身包含一个结束标记 (如空字符)

void print(const char *cp)

{

    if(cp)                //若cp不是一个空指针

        while(*cp)        //只要指针所指的字符不是空字符

            cout << *cp++;//输出当前字符并将指针向前移动一个位置

}

使用标准库规范

传入数组首元素和尾后元素的指针

void print(const int *beg, const int *end)

{

    while(beg != end)

        cout << *beg++ << endl;

}

 

显示传递一个表示数组大小的形参

第三种方法,专门定义一个表示数组大小的形参

void print (const int ia[], size_t size)

{

    for(size_t i = 0; i!=size; ++i){

        cout << ia[i] <<endl;

    }

}

需要通过size的值确定要输出多少个元素

数组形参和const

只有当函数确实要改变元素值得时候,才把形参定义成指向非常量的指针

数组引用形参

Note:

 f(int & arr[10])     //错误:将arr声明成了引用的数组

 f(int (&arr)[10])   // 正确: arr 是具有10个整数得整数数组得引用

 

传递多维数组

在处理数组的数组时,首元素本身就是一个数组,指针就是一个指向数组的指针

//matrix指向数组的首元素,该数组的元素是由10个整数构成的数组

void print(int (*martix)[10], int rowSize){/*....*/}

Note:再强调

 int *martix[10]; //10个指针构成的数组

 int (*martix)[10]  // 指向含有10个整数的数组的指针

 

6.2.5 main:处理命令行选项

 main可以传递实参

warning:当使用argv中的实参时,一定要季度可选的实参从argv[1]开始;argv[0]保存程序的名字,而非用户输入

 

6.2.6 含有可变形参的函数

有时无法预知向函数传递几个参数

如果有的实参类型相同,可以传递一个initialize_list的标准库函数;如果类型不同,可变参数模板(p618)

 initializer_list形参

如果函数的实参数量未知但是全部实参的类型都相同,可以使用名为 initializer_list 类型的形参,

表示某种特定类型的值的数组。

定义在同名头文件中

表6.1 initializer_list 提供的操作

 initializer_list<T> lst;

默认初始化;T类型元素的空列表

 initializer_list<T> lst{a,b,c,d....};

 lst的元素数量和初始值一样多;lst的元素是对应初始值的副本;列表中的元素是const

 lst2(lst) or lst2 = lst

拷贝不会拷贝列表中的元素;拷贝后,原始列表和副本共享元素

 lst.size()

 lst.begin()

 lst.end()

和vector一样lst也是一种模板类型,定义initializer_list对象时,必须说明列表中所含元素的类型:

和vector不一样的是,initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。

 void error_msg(initializer_list<string> i1){....}

使用:

 error_msg("functionX", expected,actual) //expected和actual是string

也可以包含其他形参

 省略符形参

省略符形参是为了便于C++访问特殊C代码

这些代码使用了varargs的C标准库功能。

Warning:省略符形参应该仅仅用于C和C++通用的类型。特别应该注意的是,大多数类型的对象在传递给i省略符形参时都无法正确拷贝。

只能出现在最后如

 

 void foo(parm_list, ...);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值