常引用
来源:互联网 发布:c语言计算闰年 编辑:程序博客网 时间:2024/03/29 23:06
本文讲在基于对象的程序设计中,函数中传递参数使用更广泛的技术,利用引用及常引用的话题。
先从引用的作用开始谈起。
一、引用用在参数传递中的优势:带回修改值及节省开支
先从一个经典的例子开始。
假如现在要交换两个整数,编写出的程序如下:
- //程序1
- #include <iostream>
- using namespace std;
- void swap(int x, int y); //用整形本身做形参
- int main()
- {
- int a=5,b=3;
- swap(a,b); //函数调用时传值
- cout<<"a="<<a<<" , b="<<b<<endl; //输出a=5,b=3,根本不能完成交换值
- system("pause");
- return 0;
- }
- void swap(int x,int y)
- {
- int t;
- t=x;
- x=y;
- y=t;
- }
在传统C语言中,可以利用指针实现在函数中改变实参所对应存储单元的值。
- //程序2
- #include <iostream>
- using namespace std;
- void swap(int *x, int *y);
- int main()
- {
- int a=5,b=3;
- swap(&a,&b); //将a和b的地址值传递给形式参数x和y
- cout<<"a="<<a<<" , b="<<b<<endl; //将输出a=3, b=5,交换成功
- system("pause");
- return 0;
- }
- void swap(int *x,int *y) //x指向a,y指向b
- {
- int t;
- t=*x;
- *x=*y; //对*x的修改,即是对实参a的修改
- *y=t; //对*y的修改,即是对实参b的修改
- }
在C++中,引入了引用类型专门处理此类问题。
- //程序3
- #include <iostream>
- using namespace std;
- void swap(int &x, int &y);
- int main()
- {
- int a=5,b=3;
- swap(a,b); //a即是x,b即是y
- cout<<"a="<<a<<" , b="<<b<<endl; //将输出a=3, b=5,交换成功
- system("pause");
- return 0;
- }
- void swap(int &x,int &y) //x即是a,y即是b
- {
- int t;
- t=x;
- x=y; //对x的修改,即是对实参a的修改
- y=t; //对y的修改,即是对实参b的修改
- }
略做一个总结,可以发现程序3中的诸多优势。
程序3与程序2相比,都能实现在函数中修改实参对应的值,但在实现中,不用意识到地址的存在,并且从调用的角度,swap(a,b)比swap(&a,&b)直观、简单的多,这会有效减少程序中在调用时可能犯的错误。程序2中需要两个存储地址值的单元x和y,而程序3中的x和y直接用的就是a和b的单元,从空间角度,节省了可能我们并不在意的一点点空间。
程序3与程序1相比,两者在调用的形式上完全一样,函数体的写法完全一样,仅是函数原型中有些许差别。但是,程序3之伟大之一在于,可以在函数中对实参的值进行修改,而程序1却不行。另外一个显著区别在于,程序1在调用sway()时,要为形参分配存储单元,然后将实参的值写入,而程序3中x和y直接用的就是a和b的单元,不用分配空间,也不用花时间赋值。从本例中,程序1的空间多占用8个字节(x和y分别4字节),赋值要多占用一点点时间,这点空间和时间微不足道。但是,如果形参和实参是对象,并且数据成员比较多,尤其是某些成员是数组等占用空间很大时,引用的机制带来的在开支上的节约就不是可以轻言忽略了。
综上,鉴于可以实现修改的功能,以及在空间、时间上的巨大优势,可以提高程序的执行效率。当函数参数中需要涉及对象(类)时,我们用引用类型。
引用,专为对象而生!
二、类对象的引用做形式参数
看一个例子:
- //程序4
- #include <iostream>
- using namespace std;
- class Test
- {
- private:
- int x;
- int y;
- public:
- Test(int a, int b){x=a;y=b;}
- void printxy() const;
- void setX(int n) {x=n;}
- void setY(int n) {y=n;}
- } ;
- void Test::printxy() const
- {
- cout<<"x*y="<<x*y<<endl;
- }
- void doSomething(Test &p1) //形参是引用类型
- {
- p1.setX(5);
- p1.printxy( );
- }
- void main(void)
- {
- Test t1(3,5);
- doSomething(t1); //实参是对象,t1和p1是同义词,p1占用的就是t1的地址
- <span style="white-space:pre"> </span>t1.printxy();
- system("pause");
- }
这是一件令人感到快意的事。但,问题由此而生。如果在需求中,doSomething()函数确定为不允许修改t1,这种机制不正好成了bug的温床,当程序员无意中错误地写入了诸如第22行对数据成员修改的语句,这种错误将被编译器包庇下来。假如项目灰常大,那是令人抓狂的后果。
为了限制这种无意的修改,我们想到了玻璃罩——const。
三、用对象的常引用做形参
所谓对象的常引用,就是将引用用const进行限定。自然,引用不能被修改。
将对象说明为常引用形式是:
const 类型名 &对象名;
下面是用对象的常引用做形参的例子。
- //程序5
- #include <iostream>
- using namespace std;
- class Test
- {
- private:
- int x;
- int y;
- public:
- Test(int a, int b){x=a;y=b;}
- void printxy() const;
- void setX(int n) {x=n;}
- void setY(int n) {y=n;}
- } ;
- void Test::printxy() const
- {
- cout<<"x*y="<<x*y<<endl;
- }
- void doSomething(const Test &p1) //形参是常引用
- {
- p1.setX(5); //将招致错误——error C2662: “Test::setX”: 不能将“this”指针从“const Test”转换为“Test &”
- p1.printxy( );
- }
- void main(void)
- {
- Test t1(3,5);
- doSomething(t1); //实参是对象
- system("pause");
- }
四、小结
在对象做函数的形式参数时,用对象的引用做形式参数是一个直观且高效的处理方法,提倡用好。
当不允许在函数体内对参数的值作出修改时,常将形式参数指定为const,这也是需要用好的C++的特性。
五、玻璃罩系列总结
我将const比喻为一个玻璃罩,由const决定的“常XX”的目标就是防止出现不该发生的对变量/对象的改变,“只许看不许摸”式的限制,成了一个有效的机制。
下面将限制由严格到更灵活做个排列,也作为对系列文章的总结。
方法示例含义详解链接使用常对象Test const t1;或const Test t1;对象在初始化之后,在任何情况下都不能被修改。这是最严格的限制。
(整体任何时候、任何场合都不能改)名为const的玻璃罩类中定义常数据成员class Test{
const int x;
……
}Test类的任一对象,其数据成员x 均不能被修改;访问x的成员函数也必
须为常成员函数。
(对象中的某一特定部分在任何时候、任何场合都不能改)名为const的玻璃罩类中定义常成员函数class Test{
int x;
……
void f() const;
}f 函数中,对本类的数据成员,可以访问,但不可以修改
(在本函数之外,随便;但进了本函数所管辖范围,谁都不要改,无论
是在其他场合可改变的非 const 对象,还是在其他场合也不能改变的
const对象。f 的地盘 f 做主。)名为const的玻璃罩函数参数中使用指向常对象
的指针作形式参数void f(const Test *p1, Test *p2)通过*p1访问实参的对象,无论对象是否加了const 限定,都不可以被
修改。而在同一个函数中,p2所指向的对象却是可以被修改的。
(在 f 的地盘上,根据声明区别对待,不该改的别该,该改的任你改。
——民主社会的追求。 )
(用指针避免了函数调用中“大”对象的复制,可以提高效率。)玻璃罩保护哪一个函数参数中使用指向常引用
作形式参数void f(const Test &t1, Test &t2)通过t1访问实参的对象,无论对象是否加了const 限定,都不可以被
修改。而在同一个函数中,t2所引用的对象却是可以被修改的。
(在 f 的地盘上,根据声明区别对待,不该改的别该,该改的任你改。
——这也是实现“民主”的一种途径。 )
(用引用除了可以避免了函数调用中“大”对象的复制,可以提高效率
外,其调用形式更加直观。)本文 最后一种“函数参数中使用指向常引用作形式参数”是C++中提供的精华,应该提倡在需要的时候用好。《c++编程规范——101条规则、准则与最佳实践》中也强调:
- 始终用const 限制所有指向只输入参数的指针和引用;
- 优先按const 的引用取得其他用户定义类型的输入。
- 常引用
- 常引用
- 常引用
- 常指针 和 常引用
- 常指针与常引用
- 常指针与常引用
- 7.24常指针 常对象 常引用
- 引用,指针,常引用,常指针
- 常引用,常对象,常成员函数,常数据成员~
- C++引用二常引用:
- C++引用及常引用
- 引用和常引用区别
- 引用---常引用型参数
- 对象的常引用
- C++学习:常引用
- 常引用的作用
- 6.2常引用
- 常引用学习笔记
- KMP算法
- arduino给其他芯片下载bootloader(arduino as isp)
- OpenCV 2 学习笔记(6): 使用指针来扫描图像:减少图像的位深
- Hdu 2795 Billboard
- JVM内存管理及GC
- 常引用
- Codeforces Round #194 (Div. 1) / 333A Secrets(贪心)
- 47. Lotus Notes中编程发送邮件(二)
- Android系统信息获取 之九:TelephonyManager类
- 使用Unity.Mvc3实现依赖注入简介
- php中用数组下标的方法来获取字符串的值
- 正则表达式语法
- 一种unity实物地图的精确导入的简单操作
- C primer plus 读书笔记(2)