关于函数传参的其他问题(const形参实参/可变形参)

const 形参和实参

当形参是 const 变量时,实参是 const 或者不是 const 变量都可以。 实参初始化形参时会忽略掉顶层 const:

1 void gel(const int a){
2     ;
3 }
4 
5 void gel(int a){
6     ;
7 }
8 //这两个gel函数的形参列表是等价的,因此会出现编译错误。

 

指针或引用形参与 const

 1 #include <iostream>
 2 using namespace std;
 3 
 4 void gel(int *a){
 5     ;
 6 }
 7 
 8 void gel(int &a){
 9     ;
10 }
11 
12 int main(void){
13     int i = 0;
14     const int ci = i;
15     string::size_type ctr = 0;
16     gel(&i);//调用形参是int*的gel函数
17     // gel(&ci);//错误,不能忽略底层const,即不能用指向const int的指针初始化int*
18     gel(i);//调用形参是int&类型的gel函数
19     // gel(ci);//错误,不能把普通引用绑定到const对象ci上
20     // gel(1024);//错误,非常量引用不能绑定字面值
21     // gel(ctr);//错误,类型不匹配,ctr是无符号类型的
22     return 0;
23 }

 应该尽量使用常量引用避免将普通引用形参绑定到const 对象上的错误。

 

main 函数传参:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 int main(int argc, char **argv){
 5     cout << argc << endl;
 6     for(int i = 0; i < argc; i++){
 7         cout << argv[i] << endl;
 8     }
 9     return 0;
10 }

main 函数有两个形参,通常命名为 argc 和 argv,其中 argv 是一个字符串数组,而 argc 是字符串数组的长度。其中 argv[0] 保存该源文件生成的可执行文件的名字,使用 argv 中的实参时,可选实参时从 argv[1] 开始的。

 

含有可变形参的函数:

 为了能编写能处理不同数量实参的函数,c++11 新标准提供了两种主要的方法:如果所有的实参类型相同,可以传递一个名为 initializer_list 的标准库类型,如果实参的类型不同,可以编写一种特殊的函数--可变参数模板。

c++ 还有一种特殊的形参类型--省略符 可以传递可变数量的实参。这种功能一般只用于与 C 函数交互的接口程序。

initializer_list 定义在 initializer_list 头文件中。它提供的操作有:

1     initializer_list<T> lst;//默认初始化,T类型元素的空列表
2     initializer_list<T> lst{a, b, c...};//lst 的元素和初始值一样多,lst 的元素是对应初始值的副本,列表中的元素是 const
3     lst2(lst);//拷贝或赋值一个 initializer_list 对象不会拷贝列表中的元素,拷贝后,原始列表和副本共享元素
4     lst2 = lst;
5     lst.size();//列表中元素的数量
6     lst.begin();//返回指向列表中首元素的指针
7     lst.end();//返回lst列表中的尾后指针

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

1     initializer_list<string> ls;//initializer_list 的元素类型时 string
2     initializer_list<int> li;//initializer_list 的元素类型时 int

如果时向 initializer_list 形参中传递一个值的序列,则必须把序列放在一对花括号内,且允许多次调用传递的参数数目不同:

 1 #include <iostream>
 2 #include <initializer_list>
 3 using namespace std;
 4 
 5 void error_msg(initializer_list<string> li){
 6     for(auto indx : li){
 7         cout << indx << " ";
 8     }
 9     cout << endl;
10 }
11 
12 int main(void){
13     string s1, s2;
14     cin >> s1 >> s2;
15     if(s1 != s2) error_msg({"functionX", s1, s2});
16     else error_msg({"functionX", "okay"});
17     return 0;
18 }

因为 initializer_list 包含 begin 和 end 成员,所以可以使用范围 for 循环。

对于含有 initializer_list 形参的函数,其形参列表是允许含有其他类型的形参的,而 initializer_list 形参中只能传指定类型的对象。

 1 #include <iostream>
 2 #include <initializer_list>
 3 using namespace std;
 4 
 5 void error_msg(initializer_list<string> li, int cnt){
 6     cout << cnt << ":" << endl;
 7     for(auto indx : li){
 8         cout << indx << " ";
 9     }
10     cout << endl;
11 }
12 
13 int main(void){
14     string s1, s2;
15     cin >> s1 >> s2;
16     if(s1 != s2) error_msg({"functionX", s1, s2}, 1);
17     else error_msg({"functionX", "okay"}, 2);
18     return 0;
19 }

 

省略符形参:

省略符形参是为了方便于 c++ 程序访问某些特殊的 c 代码而设置的,这些代码使用了名为 varargs 的 c 标准库功能。省略符形参应该仅仅用于 c 和 c++ 通用的类型,且大多数类型的对象在传递给省略符形参时都无法正确拷贝。

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

void gel(parm_list, ...);
void gel(...);

第一种形式指定了 gel 函数的部分形参类型,对应于这些形参的实参将会执行正确的类型检查。省略符形参所对应的实参类型无需类型检查。在第一种形式中,声明符后面的逗号是可选的。

 1 #include <iostream>
 2 #include <initializer_list>
 3 using namespace std;
 4 
 5 void gel1(string, ...){}
 6 
 7 void gel2(string ...){}//省略string后面的逗号
 8 
 9 void gel3(...){}
10 
11 void gel3(int a, int b){
12     cout << a << " " << b << endl;
13 }
14 
15 int main(void){
16     int a = 1, b = 2;
17     string s1 = "jf", s2 = "jfk";
18     char ch1 = 'f', ch2 = 'j';
19     gel1(s1, a, b, ch1, ch2);
20     // gel1(a, a, a);//错误,指定了的形参会进行类型检查
21     gel2(s1, a, b);
22     // gel3(s1, a, b);//错误,string不是c和c++通用的类型
23     gel3(a, b, ch1, ch2);
24     gel3(a, b);//输出1 2.省略号的优先级别最低,所以在函数解析时,只有当其它所有的函数都无法调用时,编译器才会考虑调用省略号函数的。 
25     return 0;
26 }

 

posted @ 2017-12-15 17:02  geloutingyu  阅读(400)  评论(0编辑  收藏  举报