C++ Primer 学习笔记11 函数(函数调用、引用形参、非引用形参)

来源:互联网 发布:办公软件学习 编辑:程序博客网 时间:2024/06/03 03:57

函数的定义

求两个int型的最大公约数

int gcd(int v1,int v2){    while (v2)    {        int temp = v2;        v2 = v1 % v2;        v1 = temp;    }    return v1;}

1、函数调用

函数名(实参);

#include <iostream>using std::cin;using std::cout;using std::endl;int gcd(int v1,int v2);int main(){    cout<<"enter two numbers:\n";int i,j;cin>>i>>j;cout<<gcd(i,j)<<endl;system("pause");return 0;}int gcd(int v1,int v2){int temp;while(v2){temp=v2;v2=v1%v2;v1=temp;}return v1;}

函数在定义或者声明时,没有显式指定返回类型是不合法的。

如果两个参数具有相同的类型,则其类型必须重复声明:

int manip(int i,j)         //error{//......}int manip(int i,int j)         //ok{//......}

参数表中不能出现同名的参数。

2、参数传递

每次调用函数时,都会重新创建该函数的所有形参,此时所传递的实参将初始化对应的形参。

形参的初始化与变量的初始化一样:如果形参具有非引用类型,则复制实参的值;如果形参为引用类型,则它只是实参的别名。

2.1、非引用形参

普通的非引用类型的参数通过复制对应的实参实现初始化。当用实参副本初始化形参时,函数并没有访问调用所传递的实参本身,因此不会修改实参的值。

int gcd(int v1,int v2){int temp;while(v2){temp=v2;v2=v1%v2;v1=temp;}return v1;}

While循环虽然修改了v1和v2的值,但这些仅局限于局部参数,而对调用gcd函数使用的实参没有任何影响。于是调用

gcd(i,j);则i与j的值不受gcd内执行的赋值操作的影响。

1、指针形参

函数的形参可以是指针,此时将复制实参指针。与其他非引用类型的形参一样,该类形参的任何改变也仅作用于局部副本。如果函数将新指针值赋给形参,主调函数使用的实参指针的值没有改变。

如果函数形参是非const类型的指针,则函数可通过指针实现赋值,修改指针所指向对象的值。

#include <iostream>using namespace std;void reset(int *ip){    *ip = 0; // changes the value of the object to which ip points    ip = 0; // changes only the local value of ip; the argument is unchanged}int main(){    int i = 42;    int *p = &i;    cout << "i: " << *p << '\n'; // prints i: 42    reset(p);                    // changes *p but not p    cout << "i: " << *p << endl; // ok: prints i: 0}

如果需要保护指针所指向对象的值,则形参需定义为const对象的指针:

void use_ptr(const int *p){}

我们既可以用int*也可以用const int*类型的实参调用use_ptr函数;但仅能用int*类型的实参传递给reset函数。这个差别来源于指针的初始化规则。可以将指向const对象的指针初始化为指向非const对象,但不可以让指向非const对象的指针指向const对象。

2、const形参

如果函数使用非引用的非const形参,则即可给该函数传递const实参也可传递非const实参。例如可以传递两个int型const对象调用gcd函数

const int i=3,j=6;int k=gcd(i,j);

如果形参定义为非引用的const类型:

void fcn(const int i){   }

则在函数中,不可以改变实参的局部副本。由于实参仍然是以副本形式传递,因此传递给fcn的既可以是const对象也可以是非const对象。

3、复制实参的局限性

复制实参并不是在所有的情况下都适合,不适宜复制实参的情况包括:

• 当需要在函数中修改实参的值时。

• 当需要以大型对象作为实参传递时。对实际的应用而言,复制对象所付出的时间和存储空间代价往往过大。

• 当没有办法实现对象的复制时。

对于上述几种情况,有效的解决办法是将形参定义为引用或指针类型。

2.2、引用形参

交换两个实参的值:

#include <iostream>using namespace std;void swap(int v1, int v2){    int tmp = v2;    v2 = v1;     // assigns new value to local copy of the argument    v1 = tmp;}               // local objects v1 and v2 no longer existint main(){    int i = 10;    int j = 20;    cout << "Before swap():\ti: "         << i << "\tj: " << j << endl;    swap(i, j);    cout << "After swap():\ti: "         << i << "\tj: " << j << endl;system("pause");    return 0;}

结果显示如下,两个实参的值并未交换,执行swap函数只是交换了实参的局部副本。


为了交换实参的值,需要将形参定义为引用类型

void swap(int &v1, int &v2){    int tmp = v2;v2 = v1;         v1 = tmp;}     

引用形参直接关联到其所绑定的对象,而并非这些对象的副本。因此,当调用swap

swap(i, j);

形参v1只是对象i的另一个名字,而v2则是对象j的另一个名字。对v1的任何修改实际上也是对i的修改。 

如果使用引用形参的唯一目的是避免复制实参,则应将形参定义为const引用。

如果函数具有非const引用形参,则不能用const对象进行调用,因为此函数可以修改传递进来的对象,这就违背了实参的const特性。





0 0
原创粉丝点击