【C++入门】(十五)高级引用和指针

1. 如何利用按引用传递来提高程序的效率

1.1 按引用传递以提高效率

  1. 请看下面这段代码,体会精神

    复制代码
    class SimpleCat
    {
    public:
        SimpleCat();            //构造函数             
        SimpleCat(SimpleCat&);  //复制构造函数 
        ~SimpleCat();           //析构函数
    };
    ​
    SimpleCat::SimpleCat()
    {
        cout << "调用构造函数SimpleCat::SimpleCat()"<<endl;
    }
    ​
    SimpleCat::SimpleCat(SimpleCat&)
    {
        cout << "调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)" << endl;
    }
    ​
    SimpleCat::~SimpleCat()
    {
        cout << "调用析构函数SimpleCat::~SimpleCat()" << endl;
    }
    ​
    SimpleCat Func1(SimpleCat theCat);
    SimpleCat* Func2(SimpleCat* theCat);
    ​
    int main()
    {
        cout << "0. 初始化一个SimpleCat对象Frisky" << endl;
        SimpleCat Frisky;
    ​
        cout << endl << "1. 调用Func1函数(传值)" << endl;
        Func1(Frisky);
    ​
        cout << endl << "2. 调用Func2函数(传引用)" << endl;
        Func2(&Frisky);
    ​
        return 0;
    }
    ​
    SimpleCat Func1(SimpleCat theCat)
    {
        cout << "调用Func1函数(传值)SimpleCat Func1(SimpleCat theCat)" << endl;
        return theCat;
    }
    ​
    SimpleCat* Func2(SimpleCat* theCat)
    {
        std::cout << "调用Func2函数(传引用)SimpleCat* Func2(SimpleCat* theCat)" << endl;
        return theCat;
    }
    ​
    //0. 初始化一个SimpleCat对象Frisky
    //调用构造函数SimpleCat::SimpleCat()
    //1. 调用Func1函数(传值)
    //调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)
    //调用Func1函数(传值)SimpleCat Func1(SimpleCat theCat)
    //调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)
    //调用析构函数SimpleCat::~SimpleCat()
    //调用析构函数SimpleCat::~SimpleCat()
    //2. 调用Func2函数(传引用)
    //调用Func2函数(传引用)SimpleCat* Func2(SimpleCat* theCat)
    //调用析构函数SimpleCat::~SimpleCat()
    复制代码
    复制代码
    0. 初始化一个SimpleCat对象Frisky
    调用构造函数SimpleCat::SimpleCat()
      //初始化了一个 SimpleCat 对象 Frisky,导致构造函数被调用
     
      
    1. 调用Func1函数(传值)
    ​
    调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)
      //调用 Func1 函数时,将 SimpleCat 对象按值传递给了它,因此将在栈中创建该 SimpleCat 对象的备份,作为调用函数的本地对象,这导致了复制构造函数被调用
      
    调用Func1函数(传值)SimpleCat Func1(SimpleCat theCat)
      //调用 Func1 函数自身的内容
      
    调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)
      //Func1 函数返回时,按值返回 SimpleCat 对象,这将创建另一个对象备份,致使复制构造函数被调用
      
    调用析构函数SimpleCat::~SimpleCat()
      //Func1 函数返回的对象没有赋给任何变量,因此该对象被丢弃,调用析构函数
      
    调用析构函数SimpleCat::~SimpleCat()
      //Func1 函数结束,其本地备份不再在作用域内,调用析构函数
    2. 调用Func2函数(传引用)
    调用Func2函数(传引用)SimpleCat* Func2(SimpleCat* theCat)
      //参数按引用传递,不会创建备份,直接调用 Func2 函数自身的内容
      //然后按引用返回 SimpleCat 对象,也不调用构造函数和析构函数
      
    调用析构函数SimpleCat::~SimpleCat()
      //全部程序结束后,Frisky 不再在作用域内,最后一次调用析构函数
    复制代码

     

  1. 看不太懂代码不重要,看输出结果体会精神,总之就是 按引用传递可提高效率

 

 

1.2 传递 const 指针

  1. 直接将指针传递给函数比较危险,容易一不小心就把对象的值给修改了

  2. 传递一个 const指针,可以同时获得按值传递的安全性和按引用传递的效率

    复制代码
    class SimpleCat
    {
    public:
        SimpleCat();               
        SimpleCat(SimpleCat&);   
        ~SimpleCat();         
    };
    ​
    SimpleCat::SimpleCat()
    {
        cout << "调用构造函数SimpleCat::SimpleCat()"<<endl;
    }
    ​
    SimpleCat::SimpleCat(SimpleCat&)
    {
        cout << "调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)" << endl;
    }
    ​
    SimpleCat::~SimpleCat()
    {
        cout << "调用析构函数SimpleCat::~SimpleCat()" << endl;
    }
    ​
    const SimpleCat* const
    Func1(const SimpleCat* const theCat);
    ​
    int main()
    {
        cout << "0. 初始化一个SimpleCat对象Frisky" << endl;
        SimpleCat Frisky;
    ​
        cout << endl << "1. 调用Funct1函数(传const指针)" << endl;
        Func1(&Frisky);
    ​
        return 0;
    }
    ​
    const SimpleCat* const
    Func1(const SimpleCat* const theCat)
    {
        cout << "调用Func1函数(传const指针)(const SimpleCat* const theCat)" << endl;
        return theCat;
    }
    ​
    //0. 初始化一个SimpleCat对象Frisky
    //调用构造函数SimpleCat::SimpleCat()
    //1. 调用Funct1函数(传const指针)
    //调用Func1函数(传const指针)(const SimpleCat* const theCat)
    //调用析构函数SimpleCat::~SimpleCat()
    复制代码

     

 

1.3 作为指针替代品的引用

  1. 使用引用比使用指针要简单,而付出的代价和获得的效率没变,且和 const 一样安全

    复制代码
    class SimpleCat
    {
    public:
        SimpleCat();               
        SimpleCat(SimpleCat&);   
        ~SimpleCat();         
    };
    ​
    SimpleCat::SimpleCat()
    {
        cout << "调用构造函数SimpleCat::SimpleCat()"<<endl;
    }
    ​
    SimpleCat::SimpleCat(SimpleCat&)
    {
        cout << "调用复制构造函数SimpleCat::SimpleCat(SimpleCat&)" << endl;
    }
    ​
    SimpleCat::~SimpleCat()
    {
        cout << "调用析构函数SimpleCat::~SimpleCat()" << endl;
    }
    ​
    const SimpleCat& Func1(const SimpleCat& theCat);
    ​
    int main()
    {
        cout << "0. 初始化一个SimpleCat对象Frisky" << endl;
        SimpleCat Frisky;
    ​
        cout << endl << "1. 调用Funct1函数(传引用)" << endl;
        Func1(Frisky);
    ​
        return 0;
    }
    ​
    const SimpleCat& Func1(const SimpleCat& theCat)
    {
        cout << "调用Funct1函数(传引用)const SimpleCat& Func1(const SimpleCat& theCat)" << endl;
        return theCat;
    }
    ​
    //0. 初始化一个SimpleCat对象Frisky
    //调用构造函数SimpleCat::SimpleCat()
    //1. 调用Funct1函数(传引用)
    //调用Funct1函数(传引用)const SimpleCat& Func1(const SimpleCat& theCat)
    //调用析构函数SimpleCat::~SimpleCat()
    复制代码

     

 

2. 如何确定在什么情况下使用引用以及在什么情况下使用指针

  1. 一般情况,引用 更清晰,使用起来更容易

  2. 引用不能重新赋值,如果需要 依次指向不同的对象,就必须使用 指针

    引用不能为NULL,如果 要指向的对象有可能是NULL的话,就必须使用 指针

  3. 如果要 从堆中分配动态内存 时,就必须使用 指针

 

 

3. 使用指针时如何避免内存问题

  1. 程序在堆中分配内存时,将返回一个指针

    必须一直让某个指针指向这块内存(指针丢失后,便无法释放该内存,进而导致内存泄露)

  2. 因此,在函数之间传递内存块时,分配内存块的函数将负责释放它(谁开发谁善后),然后按引用传递内存块中的值

    如果让一个函数分配内存,另一个函数负责释放就很危险(忘记删除或重复删除)

 

 

4. 如何避开引用使用陷阱

  1. 引用始终是另一个对象的别名,按引用传递时,要注意 引用指向的对象还在不在

  2. 返回指向堆中对象的引用

    复制代码
    class SimpleCat
    {
    public:
        SimpleCat(int a, int b);
        //SimpleCat(SimpleCat&);   
        ~SimpleCat();  
    ​
    private:
        int a = 0; 
        int b = 0;
    };
    ​
    SimpleCat::SimpleCat(int a, int b)
    {
        cout << "调用构造函数SimpleCat::SimpleCat(int a, int b),a =" << a << " ,b =" << b << endl;
    }
    SimpleCat::
    ~SimpleCat()
    { cout
    << "调用析构函数SimpleCat::~SimpleCat()" << endl; } SimpleCat& Func1(); int main()
    {
    //将Func1()返回的结果赋给了一个 SimpleCat 引用 & rname(指向堆中对象的引用) SimpleCat& rname = Func1(); ​ //该引用 & rname 指向的是Func1()堆中地址,这与堆中对象的地址相同 cout << "&rname: " << &rname<< endl; ​ //如果想释放内存,不能对引用调用 delete //便创建另一个指针 * pCat 指向引用 &rname 的地址,这确实可以释放内存,但 &rname 指向空对象 SimpleCat* pCat = &rname; delete pCat; ​ return 0; } SimpleCat& Func1()
    {
    //从堆中分配内存 new SimpleCat(),并让一个指针 * pFrisky 指向它 SimpleCat* pFrisky = new SimpleCat(5, 9); ​ //输出该指针存储的地址 cout << "pFrisky: " << pFrisky << endl; ​ //解引用,并按引用将 SimpleCat 对象返回 return *pFrisky; } //调用构造函数SimpleCat::SimpleCat(int a, int b),a =5 ,b =9 //pFrisky: 00000184C8254580 //& rname: 00000184C8254580 //调用析构函数SimpleCat::~SimpleCat()
    复制代码

   对于上诉问题的解决办法
复制代码
   //将 Func1() 的返回类型声明为指针(而非引用),并返回指针(而非指针的解引用)
   SimpleCat* Func1()
   {
       //不变
       SimpleCat* pFrisky = new SimpleCat(5, 9);
​
       //不变
       cout << "pFrisky: " << pFrisky << endl;
​
       //返回指针
       return pFrisky;
   }
复制代码
 

 

5.总结

  1. 虽然但是,还是要说:

    指针 是一个存储内存地址的 变量,而 引用别名(多数情况下,引用更好使)

  1. 如果返回的是局部对象,必须 按值返回,否则返回的引用将指向不存在的对象

    按引用返回 的效率高、节省内存且程序运行速度更快 

posted @   哟吼--小文文公主  阅读(75)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示