← 返回首页
深入理解C++引用传递与指针传递的区别
发表时间:2024-05-06 02:59:59
深入理解C++引用传递与指针传递的区别

1.引用传递

C++中的引用传递是通过引用将参数传递给函数,使函数能够直接访问传递的参数。但是,引用传递并不改变被引用对象的内存指向,而是允许函数在不复制参数的情况下对其进行操作。这意味着,虽然函数可以修改被引用对象的值,但不能修改被引用对象的地址或指向其他对象的指针。

实例:

#include <iostream>
#include <string.h>
using namespace std;

class Cat {
    public:
    // 公共成员函数
    Cat(string alias){
        this->alias= alias;
    }  

    string getAlias(){
       return this->alias;
    }

    void setAlias(string alias){
        this->alias = alias;
    }

    private:
    // 私有成员变量
    string alias;
};

void changeCat(Cat *& c){
    cout<<"\n----------changeCat is start---------------\n"<<endl;
    cout<<c->getAlias()<<endl;
    cout<<"c引用变量的值:"<<c<<endl;
    cout<<"c引用变量的内存地址:"<<&c<<endl;

    c= new Cat("huahua");
    cout<<"****changeCat函数内部改变了引用变量c的指向之后****"<<endl;
    cout<<c->getAlias()<<endl;
    cout<<"c引用变量的值:"<<c<<endl;
    cout<<"c引用变量的内存地址:"<<&c<<endl; 
    cout<<"\n----------changeCat is over---------------\n"<<endl;
}

int main(){

    Cat* cat1 =new Cat("mimi");

    Cat * &pt = cat1;

    cout<<"pt引用变量的值:"<<pt<<endl;
    cout<<"pt引用变量的内存地址:"<<&pt<<endl;

    changeCat(pt);
    printf("-------in main() 调用changeCat之后--------\n");
    cout<<pt->getAlias()<<endl;
    cout<<"pt引用变量的值:"<<pt<<endl;
    cout<<"pt引用变量的内存地址:"<<&pt<<endl;
    return 0;
}

运行结果:

pt引用变量的值:0x1eae040
pt引用变量的内存地址:0x7ffd17bb6818

----------changeCat is start---------------

mimi
c引用变量的值:0x1eae040
c引用变量的内存地址:0x7ffd17bb6818
****changeCat函数内部改变了引用变量c的指向之后****
huahua
c引用变量的值:0x1eae090
c引用变量的内存地址:0x7ffd17bb6818

----------changeCat is over---------------

-------in main() 调用changeCat之后--------
huahua
pt引用变量的值:0x1eae090
pt引用变量的内存地址:0x7ffd17bb6818

我们发现引用传递其引用c所指向的内存单元,从始至终都没有发生改变。由于这个内存单元是指针类型,我们可以修改内存单元里的值,但是不能修改内存单元本身的地址,即让引用c指向一个新的内存单元。

所以引用传递的本质是:引用传递能够将变量或对象本身作为参数传递,而不是复制一份副本后传递给形参。

引用传递的主要作用有两点:

  1. 函数内部可修改变量或对象。函数返回后,函数调用者得到的也是被修改后的值。常见场景:① 函数需要返回多个值,由于return只能返回一个值,因此可以将其他值以引用传递的形式修改。② 控制递归过程,可以令参数为引用传递,每次递归执行函数体,就会修改参数,当参数等于某个值时递归结束。
  2. 也是最重要的作用,引用传递可以避免对象传递时的复制构造。如果函数参数是对象,且采用值传递,则从调用者传到被调函数的参数,需要调用一次复制构造函数。如果这个对象很大,复制构造的开销就会很高。反观引用传递,它传递对象本身,可以完美规避复制构造的过程,极大减少时空开销。最后,如果不希望函数体更改引用传递的对象,则应在对象参数前加const限定,即const引用传递。

2.指针传递

C++中的指针传递,其本质是传递给形参的指针仍是实参的一个拷贝。这一点就和引用传递有了本质上的区别了。指针传递可以理解成实参和形参两个指针是指向同一地址的指针,你可以通过这两个指针修改这个地址上所指向的内存单元的内容,却不能通过形参去修改实参的指向。

实例:

#include <iostream>
#include <string.h>
using namespace std;

class Cat {
    public:
    // 公共成员函数
    Cat(string alias){
        this->alias= alias;
    }  

    string getAlias(){
       return this->alias;
    }

    void setAlias(string alias){
        this->alias = alias;
    }
    private:
    // 私有成员变量
    string alias;
};


void changeCat(Cat *c){
    cout<<"\n----------changeCat is start---------------\n"<<endl;
    cout<<c->getAlias()<<endl;
    cout<<"c指针变量的值:"<<c<<endl;
    cout<<"c指针变量的内存地址:"<<&c<<endl;

    c= new Cat("huahua");
    //c->setAlias("huahua");
    cout<<"****changeCat函数内部改变了指针变量c的指向之后****"<<endl;
    cout<<c->getAlias()<<endl;
    cout<<"c指针变量的值:"<<c<<endl;
    cout<<"c指针变量的内存地址:"<<&c<<endl;

    cout<<"\n----------changeCat is over---------------\n"<<endl;
}

/*
Cat * changeCat(Cat *c){

    cout<<c->getAlias()<<endl;
    cout<<&c<<endl;

    c= new Cat("huahua");
    cout<<c->getAlias()<<endl;
    cout<<&c<<endl;
    return c;
}*/

int main(){

    Cat *pt = new Cat("mimi");
    //c1 = changeCat(c1);
    cout<<"pt指针变量的值:"<<pt<<endl;
    cout<<"pt指针变量的内存地址:"<<&pt<<endl;

    changeCat(pt);

    printf("-------in main() 调用changeCat之后--------\n");
    cout<<pt->getAlias()<<endl;
    cout<<"pt指针变量的值:"<<pt<<endl;
    cout<<"pt指针变量的内存地址:"<<&pt<<endl;

    return 0;
}

运行结果:

pt指针变量的值:0x1b76040
pt指针变量的内存地址:0x7fffeb039110

----------changeCat is start---------------

mimi
c指针变量的值:0x1b76040
c指针变量的内存地址:0x7fffeb0390c8
****changeCat函数内部改变了指针变量c的指向之后****
huahua
c指针变量的值:0x1b76090
c指针变量的内存地址:0x7fffeb0390c8

----------changeCat is over---------------

-------in main() 调用changeCat之后--------
mimi
pt指针变量的值:0x1b76040
pt指针变量的内存地址:0x7fffeb039110

小结:

引用传递的本质是:引用传递能够将变量或对象本身作为参数传递,而不是复制一份副本后传递给形参。而指针传递,其本质是实参传递给形参的指针仍是实参的一个拷贝(副本)。