c++学习笔记(c++中的引用)
1.c++中的bool类型:
其实c语言中也有bool类型,如果是遵守c90标准的编译器(其实现在大量编译器都是c90标准的),对于bool类型的使用除了要使用头文件
stdbool.h外,与c++中的bool类型完全相同。如果不是c90标准,则此时的bool其实就是int类型。详细见下stdbool.h文件的源码:
[cpp]
#ifndef _STDBOOL_H_
#define _STDBOOL_H_
#define __bool_true_false_are_defined 1
#ifndef __cplusplus
#define false 0
#define true 1
#define bool _Bool
#if __STDC_VERSION__ < 199901L && __GNUC__ < 3 && !defined(__INTEL_COMPILER)
typedef int _Bool;
#endif
#endif /** !__cplusplus */
#endif /** !_STDBOOL_H_ */
c++中bool类型有几个特性:
a.理论上bool变量只占用一个字节,但是如果多个bool变量定义在一起,可能会各占一个bit,这个取决于编译器的实现。
b.bool类型是一个很严格的类型,只有true和false两个值,一切非零的值都会变成true。测试代码如下:
[cpp]
#include <stdio.h>
int main(int argc, char *argv[])
{
int a;
bool b = true;
printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));
b = 3;
a = b;
printf("a = %d, b = %d\n", a, b);
b = -5;
a = b;
printf("a = %d, b = %d\n", a, b);
a = 10;
b = a;
printf("a = %d, b = %d\n", a, b);
b = 0;
printf("b = %d\n", b);
printf("Press enter to continue ...");
getchar();
return 0;
}
2.c++中引用的概念:
1.引用的定义:
引用是c到c++升级中提出的一个新概念。引用可以看作一个已定义变量的别名。普通引用在声明的时候必须要用其他变量进行初始化,一旦初始化这个引用就不能再是其它变量的别名了。
[cpp]
<span style="white-space:pre"> </span>Type& name = var;
2.引用的作用:引用作为变量的别名,在某些情况下可以替代指针,相对指针来说具有更好的可读性和实用性。
例子:swap函数的对比:
[cpp]
void swap(int& a,int& b) //使用引用作为函数参数,进行两个数交换
{
int t = a;
a = b;
b = t;
}
swap(a,b);
[cpp]
void swap(int* a,int* b) //使用地址传递,进行两个数交换
{
int t = *a;
*a = *b;
*b = t;
}
swap(&a,&b);
可见两个程序,第二个容易被误会成为是a与b地址的交换,可读性不高。切记:引用作为函数参数的时候不用进行初始化,当调用函数的时候才进行初始化。
3.常引用(const引用):const Type& name = var; const引用是使name引用具有只读属性。
常引用的另一个用法:当使用常量,或者类型不一致的变量对const引用进行初始化时,c++编译器会为常量,或者类型不一致的变量的值分配空间,并将引用名作为这段空间的别名。也就是说使用常量对const引用初始化后将生成一个只读变量(与c语言中的只读变量意义相同)。
代码如下:
[cpp]
int main()
{
char a = 10;
const int& b = a;
//const int& b = 9;
printf("a %x\n",&a);
printf("b %x\n",&b);
return 0;
}
4.引用的实质:
引用在c++中的内部实现其实就是一个常指针,Type& name <> Type * const
name(是地址不能变的一个指针),其实每次给引用初始化的时候Type& name1= var1,就是在给Type * const
name =
&var的过程,也就是说这个地址不能变的特性决定了引用一旦初始化就不能再成为其他变量的别名。当你每次使用引用的时候,无论是作为左值还是右
值的时候,其实var1就是*var。
注意:引用实质是指针,所有引用有自己的存储空间,所占的空间大小与指针相同。
5.返回值为引用:
a.引用为函数返回值:
若返回栈变量:不能成为其它引用的初始化值(int& b = fun();)、不能成为左值(即不能被赋值 fun() = 10;)、但是可以当做右值使用(int a = fun(); 即把这个引用的值赋值给a变量)。
若返回静态变量或全局变量:可以成为其它引用的初始化值、即可以作为右值使用,也可以作为左值使用。代码如下:
[cpp]
#include <stdio.h>
int& f()
{
static int a = 0;
return a;
}
int& g()
{
int a = 0;
return a;
}
int main()
{
int a = g();
int& b = g();
f() = 10;
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("f() = %d\n", f());
printf("Press enter to continue ...");
getchar();
return 0;
}
b.c++中三目运算符的升级:c语言中的三目运算符返回的是变量的值,不能作为左值使用。c++中的三目运算符返回的是变量的引用,因此可以即当做右值也当做左值。
注意:三目运算符可能返回的值中如果有一个是常量,则不能作为左值使用,如:(a<b?1:b) = 10; 是会编译出错的。因为此时的三目运算符返回的是值,而不再是引用了。
课后思考:
1.c++中为什么不允许定义引用数
组,Type&
name[num]: 引用数组理论上是一个数组,每一个元素都是一个引用。但是数组是一段连续内存空间,所有说这些引用的地址也应该是连续的。但是引
用的地址也就是变量的地址,所以说引用数组是没有意义的,直接用原来的变量数组就可以了。换个角度再说,如果引用数组成了,那想访问这个数组,对引用取地
址&&name,不就产生二义性了吗!所以c++里面没有引用数组。
2.如何定义一个数组的引用:其实数组的引用,就是一个数组元素类型的指针的引用,如:int* &d = p;
3.数组的引用与数组指针有什么区别:数组的引用,是一个数组元素类型的指针的引用。数组指针,是一个指向数组的指针。两者没有什么关系!!!
4.如何定义一个函数的引用:函数的引用,就是函数指针的引用,如:void (* &m)(void) = q;
5.函数的引用与函数的指针有什么区别:没什么区别,函数的引用就是函数指针的引用,两者是一个东西!!!
这里有一个小例子(请仔细查看备注):
[cpp]
#include <stdio.h>
void fun(void)
{
printf("hello fun\n");
}
int main(int argc, char *argv[])
{
int a[10]={1,2,3,4,5};
int* p = a;
printf("%d\n",p[2]);
int* &d = p; //这里定义了一个数组的引用,即int*类型指针的引用
printf("%d\n",d[2]); //此时d就是p
void (*q)(void) = fun; //这里定义了一个函数指针
void (* &m)(void) = q; //这里定义了一个void (* )(void)类型的函数指针的引用
m();
//q();
int qq = 12;
int (*nl)[10] = &a;
int (*na)[10] = (int (*)[10])qq; //这里要注意这个强制类型转换的方式 (int (*)[10])为一个整体类型
//要注意给引用初始化的时候 一定要是一个变量 而不能是一个常量 这里&a是一个常量 所以应该用常引用
int (* const &n)[10] = &a;//注意a是变量 &a是常量 也可以像上面的方式一样 用一个指针过度下
int (* &pn2)[10] = (int (* &)[10])n;//同一个原理的强制类型转换 有const与没有const 完全是两个类型
int (* &pn)[10] = nl; //这里定义了一个int(* )[10]类型的数组指针的引用
int (* &pn1)[10] = pn; //因为 pn就是nl
printf("%d\n",**n);
//printf("%d\n",**pn);
printf("Press enter to continue ...");
getchar();
return 0;
}
对于这段代码,有几个要注意的问题:
1.int (*na)[10] = (int (*)[10])qq; //这里要注意这个强制类型转换的方式 (int (*)[10])为一个整体类型
2.c++是严格检查数据类型的,有const与无const完全是不同的两个类型
3.int (* const &n)[10] = &a; //要注意,给引用初始化的时候,一定要是一个变量而不能是一个常量,这里&a是一个常量,所以应该用常引用 。
4.有数组引用(变量指针的引用 int*
&a = b;),有函数引用(函数指针的引用 void (* &m)(void) = q;),有数组指针的引用(int (*
&pn)[10] = nl;),有引用函数(一个函数的返回值是一个引用 int&fun(void)),但是切记
没有引用数组!!!
c++学习笔记(c++中的引用)的更多相关文章
- ArcGIS案例学习笔记-点集中最近点对和最远点对
ArcGIS案例学习笔记-点集中最近点对和最远点对 联系方式:谢老师,135-4855-4328,xiexiaokui@qq.com 目的:对于点图层,查找最近的点对和最远的点对 数据: 方法: 1. ...
- 《Cocos2d-x游戏开发实战精解》学习笔记3--在Cocos2d-x中播放声音
<Cocos2d-x游戏开发实战精解>学习笔记1--在Cocos2d中显示图像 <Cocos2d-x游戏开发实战精解>学习笔记2--在Cocos2d-x中显示一行文字 之前的内 ...
- Struts2学习笔记-jsp中引用struts2框架
如果在jsp中需要引用struts2 框架,需在前面加上以下内容 <%@taglib prefix="s" uri="/struts-tags" %> ...
- 电磁兼容性设计学习笔记--PCB中地的布局
http://bbs.ednchina.com/BLOG_ARTICLE_3010439.HTM PCB上元器件的布局对整个PCB板的电磁兼容性影响很大,所以从事硬件电路设计的工程师很有必要学习PCB ...
- JavaScript学习笔记——JS中的变量复制、参数传递和作用域链
今天在看书的过程中,又发现了自己目前对Javascript存在的一个知识模糊点:JS的作用域链,所以就通过查资料看书对作用域链相关的内容进行了学习.今天学习笔记主要有这样几个关键字:变量.参数传递.执 ...
- Swift 学习笔记 (三) 之循环引用浅析
原创:转载请注明出处 110.自动引用计数实践 下面的例子展示了自动引用计数的工作机制.例子以一个简单的Person类开始,并定义了一个叫name的常量属性: class Person { l ...
- Java学习笔记之深入理解引用
引言:Java中数据传递的方式,除了基本数据类型是按照值传递,其它类型全部是按照引用传递,这和C++有很大区别,但是很多网上文章都解释的不清楚,甚至是错误的,在查阅资料之后,下面整理出一个比较容易理解 ...
- Python学习笔记6-Python中re(正则表达式)模块学习
今天学习了Python中有关正则表达式的知识.关于正则表达式的语法,不作过多解释,网上有许多学习的资料.这里主要介绍Python中常用的正则表达式处理函数. re.match re.match 尝试从 ...
- 设计模式学习笔记——java中常用的设计模式
单例设计模式(Singleton Pattern) 观察者模式(Observer Pattern) 工厂模式(Factory Pattern) 策略模式(Strategy Pattern) 适配器模式 ...
随机推荐
- Django 1.6 基于类的通用视图
Django 1.6 基于类的通用视图 最初 django 的视图都是用函数实现的,后来开发出一些通用视图函数,以取代某些常见的重复性代码.通用视图就像是一些封装好的处理器,使用它们的时候只须要给出特 ...
- AsyncTask加载图片
http://blog.csdn.net/sodino/article/details/7741674 http://www.cnblogs.com/weisenz/archive/2012/04/1 ...
- LINUX 暂停、继续进程
LINUX 暂停.继续进程 kill -STOP 1234 将该进程暂停. 如果要让它恢复到后台,用kill -CONT 1234 (很多在前台运行的程序这样是不行的) 如果要恢复到前台,请在当时运行 ...
- sharepoint 2010 使用自定义列表模版创建列表(1)
我们在使用sharepoint的过程中,发现一个比较好用的功能,就是“将此列表另存为模版”(save list as template),这个功能的作用是,创建一个和当前列表或者文档库一模一样的配置, ...
- Android 菜单(OptionMenu)大全 建立你自己的菜单
转自:http://www.cnblogs.com/salam/archive/2011/04/04/2005329.html 菜单是用户界面中最常见的元素之一,使用非常频繁,在Android中,菜单 ...
- magent编译安装及常见错误
安装magent到/usr/local/下 cd /usr/local mkdir magent cd magent/ wget http://memagent.googlecode.com/file ...
- 移动web开发前准备知识了解(html5、jquery)笔记
1.经常使用 插件工具 chrome插件: Mobile & Tablet Emulator(用于常见移动端适配):(重点) Mobile Emulator is an useful o ...
- Hadoop基础
Hadoop组成 包括两个核心组成:HDFS:分布式文件系统,存储海量的数据MapReduce:并行处理框架,实现任务分解和调度 搭建大型数据仓库,PB级数据的存储.处理.分析.统计等业务(搜索引擎. ...
- 不管ACM是不是屠龙之技
有一个目标,每天早上起床能让你保持斗志满满..找到自己的战场和归属. 这件事本身就是很难得的...是不是 ACM 并不重要. 你现在能从其他事情上获得这种体验么? -xiaodao
- C#核编之System.Console类
顾名思义,Console类封装了基于控制台的输入输出和错误流的操作,下面列举一些System.Console类常用的成员的,这些成员能为简单的命令行程序添加一些"情趣",例如改变背 ...