设为首页 加入收藏

TOP

c++原理之——参数传递
2017-06-22 10:23:08 】 浏览:7910
Tags:原理 参数 传递

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中如何调用C++函数 下一篇直接插入排序算法C++实现

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目