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) 适配器模式 ...
随机推荐
- leetcode 237 Delete Node in a Linked List python
题目: Write a function to delete a node (except the tail) in a singly linked list, given only access t ...
- Max Num---hdu2071
Max Num Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- CentOS7 lamp安装 centoOS6 lamp
快速lamp安装 How To Install Linux, Apache, MySQL, PHP (LAMP) stack On CentOS 7 Introduction A "LAMP ...
- HDU 4122 Alice's mooncake shop
单调队列,裸的!!坑死了,说好的“All the orders are sorted by the time in increasing order. 呢,我就当成严格上升的序列了,于是就各种错.测试 ...
- Linux 程序启停脚本
start.sh #!/bin/sh java -jar ./program.jar & echo $! > /var/run/program.pid stop.sh #!/bin/sh ...
- 【STL】算法 — partial_sort
partial_sort接受一个middle迭代器,使序列中的middle-first个最小元素以递增顺序排序.置于[first, middle)内.以下是測试代码: #include <ios ...
- Linq 中的Select事例
---恢复内容开始--- 1.对查询结果进行转换. string[] names={"ADE","Jerry","Steves"}; var ...
- 使用float属性布局时父元素高度不能自适应的解决方法
在网页的布局过程中,经常会用到float属性来实现页面的左右布局,但是有个问题就是父元素的高度并不能根据子元素的高度自适应.比如下面这段代码: <!DOCTYPE html> <ht ...
- OOP组合和继续的优缺点
—— 详解继承与组合的优缺点 组合与继承都是提高代码可重用性的手段.在设计对象模型时,可以按照语义来识别类之间的组合关系和继承关系.在有些情况下,采用组合关系或者继承关系能完成同样的任务,组合和继 ...
- XPath在asp.net中查询XML
.NET Framework 2.0中可以使用System.Xml.XPath命名空间下的类对XML文档进行基于路径的查询,在查询过程中需要构造类似SQL的查询字符串,该字符串遵循XPath语法.它由 ...