zoukankan      html  css  js  c++  java
  • 【C++学习教程07】引用

    参考

    • 范磊C++(第9课时)
    • Xcode VS2015

    内容

    什么是引用

    在这里插入图片描述

    在这里插入图片描述

    引用的地址

    #include <iostream>
    using namespace std;
    int main(int argc, const char * argv[]) {
        int a;
        int &ra=a;//引用需要初始化
        cout<<"a:	"<<&a<<endl;
        cout<<"ra:	"<<&ra<<endl;
        return 0;
    }
    

    输出结果:
    在这里插入图片描述

    引用就是别名变量

    在这里插入图片描述

    #include <iostream>
    using namespace std;
    int main(int argc, const char * argv[]) {
        int a;
        int &ra=a;//引用需要初始化
        a=999;
        cout<<"&a:	"<<&a<<endl;
        cout<<"&ra:	"<<&ra<<endl;
        int b=888;
        ra=b;
        cout<<"&a:	"<<&a<<endl;
        cout<<"&ra:	"<<&ra<<endl;
        cout<<"&b:	"<<&b<<endl;
        cout<<"a:	"<<a<<endl;
        cout<<"ra:	"<<ra<<endl;
        cout<<"b:	"<<b<<endl;
        ra=1;
        cout<<"a:	"<<a<<endl;
        cout<<"ra:	"<<ra<<endl;
        cout<<"b:	"<<b<<endl;
        //&ra=b;//非法操作
        return 0;
    }
    

    输出结果:

    在这里插入图片描述

    引用对象

    #include <iostream>
    using namespace std;
    class Human
    {
    public:
        int get()const{return i;}
        void set(int x){i=x;}
    private:
        int i;
    };
    
    int main(int argc, const char * argv[]) {
        Human Mike;
        Human &rMike=Mike;
        rMike.set(123);
        cout<<rMike.get()<<endl;
    }
    

    输出结果:
    在这里插入图片描述

    空引用

    在这里插入图片描述

    按值传递

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    按址传递

    按别名传递

    指针出错率高,且不易阅读。

    在这里插入图片描述

    利用指针和引用返回多值

    在这里插入图片描述

    例子略。

    按值传递对象

    在这里插入图片描述在这里插入代码片

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    
    class A
    {
    public:
    	A() { cout << "执行构造函数创建一个对象" << endl; }
    	A(A&) { cout << "执行复制构造函数创建该对象的副本" << endl; }//带参数的构造函数
    	~A() { cout << "执行析构函数删除该对象"<< endl; }
    };
    A func(A one) //返回值是类A的对象,输入值也是类A的一个对象。
    {
    	return one;
    }
    int main(int argc, const char * argv[]) {
    	A a;
    	func(a);//按值传递
    	system("pause");
    	return 0;
    }
    

    输出结果:

    在这里插入图片描述
    注意赋值构造函数的含义!!

    按址传递对象

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    
    class A
    {
    public:
    	A() { cout << "执行构造函数创建一个对象" << endl; }
    	A(A&) { cout << "执行赋值构造函数创建该对象的副本" << endl; }//带参数的构造函数
    	~A() { cout << "执行析构函数删除该对象"<< endl; }
    };
    A* func(A *one) //返回值是类A的对象,输入值也是类A的一个对象。
    {
    	//return *one;//按照值返回,也会调用赋值构造函数
    	return one;//返回一个地址
    }
    int main(int argc, const char * argv[]) {
    	A a;
    	func(&a);//按址传递
    	system("pause");
    	return 0;
    }
    

    输出结果:

    在这里插入图片描述

    使用const指针来传递对对象

    在这里插入图片描述

    在这里插入图片描述
    在这里插入图片描述

    但是使用const会很麻烦

    用别名的方式来传递对象

    省略了使用const的复杂。

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	A() { cout << "执行构造函数创建一个对象" << endl; }
    	A(A&) { cout << "执行复制构造函数创建该对象的副本" << endl; }//带参数的构造函数
    	~A() { cout << "执行析构函数删除该对象"<< endl; }
    	void set(int i) { x = i; }
    	int get() const { return x; }
    private:
    	int x;
    };
    const A& func(A &one) 
    {
    	return one;
    }
    int main(int argc, const char * argv[]) {
    	A a;
    	a.set(11);
    	const A &b = func(a);//这样通过别名就不能改变a
    	//A b = func(a);//不能将引用赋给对象
    	cout << b.get() << endl;
    	system("pause");
    	return 0;
    }
    

    输出结果:

    在这里插入图片描述
    引用实现了与指针相同的效果且不用const的,操作起来更加方便。

    指针还是引用

    • 引用只可以被初始化,但是指针能够赋值;
    • 指针可以为空但是引用必须初始化;
    • 堆中的内存必须用指针来访问,申请堆的时候返回的是指针。
    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    int main(int argc, const char * argv[]) {
    	int *p = new int;
    	if (p != NULL)
    	{
    		int &r = *p;//将r初始化为p指向的内存空间中数据的别名。
    		r = 3;
    		cout << r << endl;
    	}
    	//r = 4;//并且r的寿命只在大括号范围内有效。
    	system("pause");
    	return 0;
    }
    

    引用容易犯的错误

    最后几课时需要好好学习!

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	A(int i) { cout << "执行构造函数创建一个对象"<< endl; x = i; }
    	A(A&a) { x = a.x; cout << "执行复制构造函数创建一个对象"<< endl; }//复制构造函数
    	~A(){ cout << "执行析构函数" << endl; }
    	int get()const { return x; }
    private:
    	int x;
    };
    A func()//返回创建对象a的别名 //按值传递时返回的也是副本的值,其生存期大于t它的引用的生存期。//指针就没问题
    {
    	cout << "跳转到func函数中" << endl;
    	A a(23);// a在大括号后寿命就结束,a消失了,返回的就是一个并不存在的对象的别名。
    	cout << "对象a的地址:"<<&a << endl;
    	return a;
    }
    
    int main(int argc, const char * argv[]) {
    	A *r = &func();//并不存在的对象的别名
    	cout << "对象a的副本的地址:" << r << endl;
    	cout << r->get() << endl;
    	system("pause");
    	return 0;
    }
    

    具体分析见课件

    在这里插入图片描述

    引用一个按值返回的堆中对象

    • 错误例子
    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	A(int i) { cout << "执行构造函数创建一个对象"<< endl; x = i; }
    	A(A&a) { x = a.x; cout << "执行复制构造函数创建一个对象"<< endl; }//a是堆中对象的别名->执行后p指针无效被销毁(造成内存泄漏),这个程序只能访问其副本的地址。
    	~A(){ cout << "执行析构函数" << endl; }
    	int get()const { return x; }
    private:
    	int x;
    };
    A func() //按值返回的函数
    {
    	cout << "跳转到func函数中" << endl; 
    	A *p=new A(99);
    	cout << "堆中对象的地址:"<<p<< endl;
    	return *p;//读到堆中对象,创建其副本->复制构造函数
    }
    
    int main(int argc, const char * argv[]) {
    	A &r = func();//读到的是副本的地址
    	cout << "堆中对象的副本的地址:" << &r << endl;//地址证明他只是副本的地址
    	cout << r.get() << endl;//引用延长了临时变量的声明(也就是副本的)
    	system("pause");
    	return 0;
    }
    

    输出结果:
    在这里插入图片描述
    报错原因:
    在这里插入图片描述

    引用一个按别名返回的堆中对象

    在这里插入图片描述

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	A(int i) { cout << "执行构造函数创建一个对象"<< endl; x = i; }
    	A(A&a) { x = a.x; cout << "执行复制构造函数创建一个对象"<< endl; }//a是堆中对象的别名->执行后p指针无效被销毁(造成内存泄漏),这个程序只能访问其副本的地址。
    	~A(){ cout << "执行析构函数" << endl; }
    	int get()const { return x; }
    private:
    	int x;
    };
    A& func() //按引用返回的函数
    {
    	cout << "跳转到func函数中" << endl; 
    	A *p=new A(99);
    	cout << "堆中对象的地址:"<<p<< endl;
    	return *p;//返回引用注意!!
    }
    
    int main(int argc, const char * argv[]) {
    	A &r = func();//引用
    	cout << "堆中对象的副本的地址:" << &r << endl;//地址证明他只是副本的地址
    	cout << r.get() << endl;//引用延长了临时变量的声明(也就是副本的)
    	A *p = &r;
    	delete p;//删除p所指向的内存空间//所以调用了析构函数//r变成了空别名
    	cout << r.get() << endl;//致命的错误
    	system("pause");
    	return 0;
    }
    

    输出结果:
    在这里插入图片描述

    在哪里创建就在哪里释放

    在这里插入图片描述唯一正确无误的程序,推荐使用

    #include "stdafx.h"
    #include <stdlib.h>
    #include <iostream>
    using namespace std;
    class A
    {
    public:
    	A(int i) { cout << "执行构造函数创建一个对象"<< endl; x = i; }
    	A(A&a) { x = a.x; cout << "执行复制构造函数创建一个对象"<< endl; }
    	~A(){ cout << "执行析构函数" << endl; }
    	void set(int i) { x = i; }
    	int get()const { return x; }
    private:
    	int x;
    };
    A& func(A &a) 
    {
    	cout << "跳转到func函数中" << endl; 
    	a.set(66);
    	return a;
    }
    
    int main(int argc, const char * argv[]) {
    	A *p = new A(99);//在main中创建
    	func(*p);
    	cout<< p->get()<<endl;
    	delete p;//在main中释放
    	system("pause");
    	return 0;
    }
    

    输出结果:
    在这里插入图片描述

  • 相关阅读:
    SQL函数——LENGTH()和LENGTHB()
    简单实用的Windows命令(二)
    简单实用的Windows命令(一)
    简单jQuery实现选项框中列表项的选择
    .net开发笔记(十六) 对前部分文章的一些补充和总结
    .Net开发笔记(十五) 基于“泵”的TCP通讯(接上篇)
    .Net开发笔记(十四) 基于“泵”的UDP通信(接上篇)
    .net开发笔记(十三) Winform常用开发模式第一篇
    .net开发笔记(十二) 设计时与运行时的区别(续)
    Mybatis Spring multiple databases Java configuration
  • 原文地址:https://www.cnblogs.com/vrijheid/p/14222991.html
Copyright © 2011-2022 走看看