/*按地址传递*/
#include <iostream>
using namespace std;
void swap(int *a, int *b)
{
int c;
c = *a;
*a = *b;
*b = c;
}
int main()
{
int a = , b = ;
cout << "交换前" << "a: " << a << " b: " << b << endl;
swap(&a, &b); // 按地址传递
cout << "交换后" << "a: " << a << " b: " << b << endl;
return ;
}

按别名传递

/*按别名传递*/
/*我们可以将a和b的别名传递到swap函数中,将swap函数的接收参数改为接收两个别名,调用时候将a和b传递进去即可,
这样参数a和b就变成了主函数中的a和b的别名,由于别名即自身,所以对别名的操作即是对main函数的a和b的操作,
或者说参数a和b即main函数中的a和b*/
#include <iostream>
using namespace std;
void swap(int &a, int &b)
{
int c;
c = a;
a = b;
b = c;
}
int main()
{
int a = , b = ;
cout << "交换前" << "a: " << a << " b: " << b << endl;
swap(a, b);
cout << "交换后" << "a: " << a << " b: " << b << endl;
return ;
}

按值传递比较消耗系统资源,下面来演示

/*按值传递对象*/
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
};
A fun(A one)
{
return one;
}
int main()
{
A a;
fun(a);
return ;
}

上面代码如果改成按地址传递就会少调用一次复制构造函数,当然跟着也会少调用一次析构函数,当然如果仍然返回一个值的话,

仍然会调用一次复制构造函数来创建一个返回值,仍然浪费了系统资源,

#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
};
A fun(A *one)
{
return *one;
}
int main()
{
A a;
fun(&a);
return ;
}

当然如果仅仅返回一个地址的话,就会省去上面的因要返回一个值而调用复制构造函数和析构函数的过程

/*按值传递对象*/
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
};
A *fun(A *one)
{
return one;
}
int main()
{
A a;
fun(&a);
return ;
}

按值传递虽然可以避免重复调用复制构造函数和析构函数 ,但是由于它得到了该对象的内存地址,可以随时修改该对象的数据。所以它实际上是破坏了按值传递的保护机制,不过我们仍然有解决办法,那就是用const指针来接收对象,这样就可以防止任何试图对该对象进行操作的行为,并且保证返回一个不可被修改的对象

这样的话我们无法通过返回的地址来修改对象的值,但是我们仍然可以通过该对象的名字来修改该对象。因为指向常量的长指针只是限制我们用该指针修改它指向的对象的值,但是它并不会改变原始对象的属性,不修改该对象的值的操作可以利用传递回来的地址进行,

注意:子函数返回的指向常量的长指针的值 必须用指向常量的长指针来接收;否则会报错!!!!!!!!!!!!!!!!!!!!!!!!

/*注意不要用对象来接收返回的别名,由于别名并不是对象,只是原来对象的另一个名字,所以呢执行复制构造函数以后,并没有*/
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
int get()const{return x;}
void set(int i) {x = i;}
private:
int x;
};
const A *const fun(const A *const one) //保证传进来的数据不被修改,返回的值也不被修改
{
one->get();
return one;
}
int main()
{
A a;
const A *const p = fun(&a);
a.set();
cout << "p:" << p << endl;
cout << "a:" << &a << endl;
return ;
}

下面是引用的代码,注意当子函数返回一个引用的时候不能用一个对象来接收该引用,这个对象是不会得到一个对象的数据的,因为返回的仅仅是一个引用的名字而已,而要定义一个引用来接收返回的引用,如果返回一个对象的时候倒是可以定义一个对象来接收

/*注意不要用对象来接收返回的别名,由于别名并不是对象,只是原来对象的另一个名字,
即返回的不是对象,而是对象的另一个名字,所以不能用对象来接收一个别名,而要用一个别名来接收它
如果返回的是一个对象的话就可以用一个对象来接收它,这样执行复制构造函数的时候也会复制返回的对象的数据
所以执行复制构造函数之后并没有复制该对象的数据*/ /*别名常量不能修改它所引用的对象的数据const A &b = a; 即定义一个类A中a对象的别名常量b,*/
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
int get()const{return x;}
void set(int i) {x = i;}
private:
int x;
};
A& fun(A &one)
{
one.get();
return one;
}
int main()
{
A a;
A &b = fun(a);
a.set();
cout <<b.get()<< endl;
return ;
}

引用本来就是常量,我们不能改变它所引用的对象,而且当我们不想让该引用修改它所引用的对象的值的时候,我们可以把它定义为别名常量,

这个时候用该引用修改原对象的名字就是非法的,会报错,只能用原对象的名字来修改这个对象

/*别名常量不能修改它所引用的对象的数据const A &b = a; 即定义一个类A中a对象的别名常量b,这时候不能用b修改a的数据*/
#include <iostream>
using namespace std;
class A
{
public:
A() {cout << "执行构造函数创造一个对象\n";}
A(A&) {cout << "执行复制函数创建该对象的副本\n";}
~A() {cout << "执行析构函数删除该对象\n";}
int get()const{return x;}
void set(int i) {x = i;}
private:
int x;
};
const A& fun(const A &one) //保证返回的值不被修改,传进来的对象也不被修改
{
one.get();
return one;
}
int main()
{
A a;
const A &b = fun(a);
a.set();
cout <<b.get()<< endl;
return ;
}

c++的引用(二)的更多相关文章

  1. Unity Inspector 给组件自动关联引用(二)

    通过声明的变量名称,主动关联引用. 使用这个关联引用两种方式1.  给你组件继承  MonoAutoQuote 点击组件inspector 按钮执行2.  给你组件类添加[AAutoQuote] 特性 ...

  2. JDK1.8新特性之(二)--方法引用

    在上一篇文章中我们介绍了JDK1.8的新特性有以下几项. 1.Lambda表达式 2.方法引用 3.函数式接口 4.默认方法 5.Stream 6.Optional类 7.Nashorm javasc ...

  3. C语言教学--二维数组和指针的理解

    对于初学者对二维数组和指针的理解很模糊, 或者感觉很难理解, 其实我们和生活联系起来, 这一切都会变得清晰透彻. 我们用理解一维数组的思想来理解二维数组, 对于一维数组,每个箱子里存放的是具体的苹果, ...

  4. 【学习笔记】【C语言】二维数组

    1. 什么是二维数组 一个数组能表示一个班人的年龄,如果想表示很多班呢? 什么是二维数组?int ages[3][10]; 三个班,每个班10个人 相当于3行10列 相当于装着3个一维数组 二维数组是 ...

  5. jenkins-APP打包页面展示二维码

    背景: 客户要求在APP打包页面展示二维码.虽然感觉这个功能很鸡肋,但是还是加上吧. 效果展示: 配置: 在上图中,106对应的内容是BuildName,我们可以通过build-name-setter ...

  6. 【Java学习笔记之八】java二维数组及其多维数组的内存应用拓展延伸

    多维数组声明 数据类型[][] 数组名称; 数据类型[] 数组名称[]; 数据类型数组名称[][]; 以上三种语法在声明二维数组时的功能是等价的.同理,声明三维数组时需要三对中括号,中括号的位置可以在 ...

  7. java_方法引用

    什么是方法引用? 个人简述方法引用: 方法引用主要是针对已经有的方法来让目前的编程更加简洁 当我们想要使用一个接口的子类的时候,子类需要重写这个接口中的抽象方法, 被重写的这个方法参数列表固定,返回值 ...

  8. Block 循环引用(上)

    iOS的内存管理机制 Objective-C在iOS中不支持GC(垃圾回收)机制,而是采用的引用计数的方式管理内存. 引用计数:在引用计数中,每一个对象负责维护对象所有引用的计数值.当一个新的引用指向 ...

  9. VS2015+OpenGL4.0开发编译时弹出错误:glaux.lib(tk.obj) : error LNK2019: 无法解析的外部符号 _sscanf,该符号在函数 _GetRegistrySysColors@8 中被引用

    一.问题描述: VS2015+OpenGL4.0开发编译时弹出如下所示的错误: 1>glaux.lib(tk.obj) : error LNK2019: 无法解析的外部符号 _sscanf,该符 ...

  10. 《C语言程序设计》指针篇<二>

    通过指针引用多维数组 如何理解二维数组元素的地址? 要知道,这本书用了整整两页的内容来讲解这方面的知识,从这里足以看出来理解通过指针来引用二维数组是一件比较麻烦的事情,但是我认为理解并不难. 什么是二 ...

随机推荐

  1. UVa1584 Circular Sequence

    #include <stdio.h>#include <string.h> int less(char* str, size_t len, size_t p, size_t q ...

  2. 【MFC相关】MFC入门相关

    1.MFC的“匈牙利标识符命名法”,这是一个约定,可以增加代码的可读性: 声明或定义了一个类,那么这个类可以以“C”(class)为前缀,如CHelloWorldDlg类: 定义一个无符号型的局部变量 ...

  3. elasticsearch-5.0.0初见

    基础概念 Elasticsearch有几个核心概念.从一开始理解这些概念会对整个学习过程有莫大的帮助. 接近实时(NRT) Elasticsearch是一个接近实时的搜索平台.这意味着,从索引一个文档 ...

  4. .net Web应用程序使用IIS调试

    1.这种调试方式是区别于使用Visual Studio 自带的调试方式 2.点击[创建虚拟目录],成功

  5. Python之三层菜单

    三层菜单,根据用户所选数字,进入子菜单.一级一级呈现. menu = { 'Beijing': { "ChaoYang": { "CBD": ['CICC', ...

  6. Android Launcher label和Main Activity保持不一致

    最近在开发一个库存管理的App,AndroidMainifest.xml中是这样设定的: <application android:allowBackup="true" an ...

  7. Tensorflow 神经网络

    Tensorflow让神经网络自动创造音乐 前几天看到一个有意思的分享,大意是讲如何用Tensorflow教神经网络自动创造音乐.听起来好好玩有木有!作为一个Coldplay死忠粉,第一想法就是自动生 ...

  8. 【Kill】两条Linux命令彻底杀死Oracle

    今天编写的两条极具杀伤力的命令,它可以瞬间将Oracle杀死在无形之中.后面我将给出简单注释并展示一下它的威力.$ ps -ef |grep $ORACLE_SID|grep -v grep|awk ...

  9. 在C#中调用API获取网络信息和流量

    原文 在C#中调用API获取网络信息和流量 最近一项目中要求显示网络流量,而且必须使用C#. 事实上,调用 IpHlpApi.dll 的 GetIfTable API 可以轻易获得网络信息和网络流量. ...

  10. Hibernate JPA中@Transient、@JsonIgnoreProperties、@JsonIgnore、@JsonFormat、@JsonSerialize等注解解释

    @jsonignore的作用作用是json序列化时将java bean中的一些属性忽略掉,序列化和反序列化都受影响. http://www.cnblogs.com/toSeeMyDream/p/443 ...