频道栏目
首页 > 程序开发 > 软件开发 > C++ > 正文
c++原理之——参数传递
2017-06-21 09:33:53         来源:forDreamYue的博客  
收藏   我要投稿

c++原理之——参数传递

1、按值传递

简单来说,在给一个函数传递参数时,该函数获得的参数只是你传递的参数的副本,彼此之间分开存储,不共享一片内存。

举个例子

void swap(int x,int y)  
{  
    int temp=x;  
    x=y;  
    y=temp;  
}  
int main()  
{  
    int a=3;  
    int b=4;  
    swap(a,b);  
    cout<<"a="<<a<<", b="<<b<<endl;  
}  

结果输出"a=3, b=4"。

cout<<"a="<显然,swap函数并没有起到作用,为什么呢?因为在调用swap(a,b);的时候,传递swap函数的形参x和y的并不是a和b本身,而是存储在另一个地方的a和b的值,通俗地讲,也就是a和b的值的副本。你无法通过对副本的操作去改变本体。编译后的汇编代码

call    ___main  
movl    $3, -12(%ebp)  
movl    $4, -16(%ebp)  
movl    -16(%ebp), %eax  
movl    %eax, 4(%esp)  
movl    -12(%ebp), %eax  
movl    %eax, (%esp)  
call    __Z4swapii  
subl    $16, %esp  
movl    8(%ebp), %eax  
movl    %eax, -4(%ebp)  
movl    12(%ebp), %eax  
movl    %eax, 8(%ebp)  
movl    -4(%ebp), %eax  
movl    %eax, 12(%ebp)  

在底层上,a和b存储在内存中,在调用swap函数的之前,main函数会把a和b的值的压入栈中,接着调用swap函数,swap函数便可以拿栈中的值进行运算,swap函数返回后,控制又回到main函数上。栈中的a和b的值交换,并不会改变存储在内存中a和b本身的值。

2、指针传递

简单来说,在给一个函数传递参数的时候,该函数获得的是你传递参数的地址的值,任何对该地址的操作,都会引起参数的改变。举个例子

void swap(int *x,int *y)  
{  
    int temp=*x;  
    *x=*y;  
    *y=temp;  
}  
int main()  
{  
    int a=3;  
    int b=4;  
    swap(&a,&b);  
    cout<<"a="<<a<<", b="<<b<<endl;  
}  

结果输出"a=4, b=3"。

swap函数起作用了,来看看发生了什么,传递给swap函数的形参x和y的是参数a和b的地址,而swap函数直接对两个参数的地址进行解引用,意味着直接在存储a和b的内存上改变a和b的值,所以main函数中a和b的值会发生改变。

在底层上,指针传递的实现和按值传递的实现几乎是一样的,不同的是指针传递是main函数把a和b的地址压入栈中,而按值传递是main函数把a和b的值压入栈中,前者调用的函数拿到的是参数的地址,后者调用的函数拿到的仅仅是参数的值,而且该值存储在与参数存储内存不一样的地方,仅仅是一个副本。

3、引用传递

简单来说,引用传递在底层上的实现跟指针传递是一样的,但C++为引用传递添加了一点东西,使得引用传递有自己的特点。

1)、当引用被创建时,它必须被初始化(指针则可以在任何时候被初始化)

2)、一旦一个引用被初始化为指向一个对象,它就不能改变为另一个对象的引用(指针则可以在任何时候指向另一个对象)。

3)、不可能有NULL引用。必须确保引用是和一块合法的存储单元关联(指针可以置为NULL)。

下面的汇编代码对应上面指针传递的main函数代码,也对应于上面引用传递的的main函数代码,两者的产生的汇编代码是等价的。
 

call    ___main  
movl    $3, -28(%ebp)  
movl    $4, -32(%ebp)  
leal    -32(%ebp), %eax  
movl    %eax, 4(%esp)  
leal    -28(%ebp), %eax  
movl    %eax, (%esp)  
call    __Z4swapRiS_ 
subl    $16, %esp  
movl    8(%ebp), %eax  
movl    (%eax), %eax  
movl    %eax, -4(%ebp)  
movl    12(%ebp), %eax  
movl    (%eax), %edx  
movl    8(%ebp), %eax  
movl    %edx, (%eax)  
movl    12(%ebp), %eax  
movl    -4(%ebp), %edx  
movl    %edx, (%eax)  

举个例子
 

void swap(int &x,int &y)  
{  
    int temp=x;  
    x=y;  
    y=temp;  
}  
int main()  
{  
    int a=3;  
    int b=4;  
    swap(a,b);  
    cout<<"a="<<a<<", b="<<b<<endl;  
}  

结果输出"a=4, b=3"。

本质上,引用传递在底层上和指针传递的实现方式是一样的,我们可以认为引用仅仅是语法上的一种不同方法(有时称为“语法糖”)。什么是语法糖,举个例子,a[i]和*(a+i)本质上是一样的,但a[i]的可读性更强,比*(a+i)更加直观容易理解,语法糖使得程序更加不容易出错。

同样的,引用传递虽然在底层的实现上和指针传递一样,但是从语言来说,引用不等于指针,因为c++给引用赋予了一些特性,这些特性使得引用传值在某些方面比指针传值要好,比如你不必担心参数是否被初始化了(编译器强迫它初始化),也不必知道怎样对它间接引用(这由编译器做)。

点击复制链接 与好友分享!回本站首页
上一篇:深入理解C++中public、protected及private用法
下一篇:(Effective C++) Item 29:争取异常安全的代码
相关文章
图文推荐
文章
推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站