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) 适配器模式 ...
随机推荐
- Holding Bin-Laden Captive!(hdoj1085)代码并未完全看懂
We all know that Bin-Laden is a notorious terrorist, and he has disappeared for a long time. But rec ...
- js中一些常用的基本函数
如何使用jquery刷新当前页面下面介绍全页面刷新方法:有时候可能会用到window.location.reload()刷新当前页面.parent.location.reload()刷新父亲对象(用于 ...
- 【the service mysql57 failed the most】
异常信息: the the service mysql57 failed the most recent status change request with the messagethe servi ...
- Windows Azure 的开源 DNA
去年年底,第二期微软云加速器在中国正式启动,17 家创业公司入选.依靠云计算的 HTML 5 专业富媒体动画平台 Mugeda(乐享云)是其中之一.微软云加速器为创业公司提供大量支持,但 Mugeda ...
- Python学习笔记10-Python MysqlHelper ,MySql 辅助类
自己写了一个MySql辅助类,有需要的拿走: #--encoding:utf-8-- # import MySQLdb class MySQLHelper: myVersion=0.1 def __i ...
- js实现车轮的来回滚动
最近喜欢用js做车轮的来回滚动,简单的js动画分享给大家.有什么建议记得说出来大家一起讨论哦!效果图如下: 源代码: <style> #pic1{ width:20px; height:2 ...
- H264 编码详解
H264 编码详解(收集转载) (1) x264_param_default( x264_param_t *param ) 作用: 对编码器进行参数设定 cqm:量化表相关信息 csp: ...
- ASP.NET 委托,异步调用例子 .
简要介绍:1.定义异步执行需要调用的方法2.定义具有与异步执行方法相同签名的委托(Delegate):3.调用 BeginInvoke 和 EndInvoke 方法. 3.1. BeginInvo ...
- ok6410驱动usb摄像头
为了做图像处理,须要用摄像头,搜到实验室仅仅有一个摄像头,是国安的.详细參数在终端中看到: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdGluZzEyM ...
- 好用的侧边栏菜单/面板jQuery插件
我想大家都用过一些APP应用,它们的菜单展示是以侧边栏滑动方式展现,感觉很新鲜,而现在网页设计也是如此,不少网站也效仿这样的方式来设计.使用侧边栏的好处就是可以节约空间,对于一些内容多或者喜欢简约的网 ...