首页 > 编程语言 >【C++入门】(六)高级引用和指针

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

时间:2022-09-23 11:02:38浏览次数:60  
标签:Func1 调用 入门 函数 C++ SimpleCat 引用 指针

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. 如果返回的是局部对象,必须 按值返回,否则返回的引用将指向不存在的对象

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

标签:Func1,调用,入门,函数,C++,SimpleCat,引用,指针
From: https://www.cnblogs.com/ZWJ-zwj/p/16721952.html

相关文章

  • 【C++入门】(三)创建指针
    1.指针是什么?1.1理解指针及其用途变量是可存储一个值的对象:整型变量存储一个数字;字符变量存储一个字母;指针是存储内存地址的变量计算机内存是存储变量......
  • 【办公自动化】正则表达式的入门及提高学习网站
    这个网站有入门101课程,带中文的。强烈推荐!https://regexlearn.com/zh-cn/learn/regex101记录一下学习心得:1、abcd*和abcd+......
  • 【C++入门】(四)开发高级指针
    1.如何在堆中创建对象?1.1在堆中创建对象定义了类型Cat后,便可声明一个指向这种对象的指针,并在堆中实例化一个Cat对象,就像在栈中实例化一样Cat*pCat=newCat;......
  • 【C++入门】(一)创建基本类
    1.类型是是什么?类型是一个包含数据和功能的对象 2.什么是类和对象?C++类是一个模板,用于创建对象。类是一系列捆绑在一起的变量和函数,变量构成了类的数据,......
  • C入门第一笔
    C语言源代码(由高级语言编写C++、Java等)—>通过C语言编译程序编译—>二级制机器指令(0和1)源程序......
  • C++ "链链"不忘@必有回响之双向链表
    C++"链链"不忘@必有回响之双向链表1.前言写过一篇与单链表相关的博文(https://blog.51cto.com/gkcode/5681771),实际应用中,双向循环链表的功能更强大。单链表中,查询一个......
  • cesium 入门指南
    最近拿到了几份offer,经过这次找工作发现自己最近脱节挺严重,为了后续的职业发展,决定开始书写博客记录自己的努力。cesium属于跨平台、跨浏览器的展现三维地球、地图的Java......
  • 「浙江理工大学ACM入队200题系列」问题 A: 零基础学C/C++34—— 3个数比较大小(冒泡排
    深夜写的,代码都还没来得及跑一便,可能有错误,欢迎指出,后续会检验一遍并修改错误.本题是浙江理工大学ACM入队200题第四套中的A题,同时给出了冒泡排序和选择排序算法......
  • 从汇编看C++函数返回对象
    同样的代码,在msvc和gcc里面实现不同。structTest{inta;intb;intc;intd;~Test(){std::cout<<"end"<<std::endl;}};TestgetTest(){Testsa;sa.a=1......
  • NLP新手入门指南|北大-TANGENT
    开源的学习资源:《NLP新手入门指南》,项目作者为北京大学TANGENT实验室成员。该指南主要提供了NLP学习入门引导、常见任务的开发实现、各大技术教程与文献的相关推荐等......