由c到c++
oop第一课
c语言的局限
c++的特点
c++的程序特征
c++程序的结构特性
c++程序的编辑、编译和运行
c++对c的补充
c语言的局限
类型检查机制相对较弱,使得程序中的一些错误不能在编译时由编译器检查出来。
c语言本身没有支持代码重用的语言结构
不适合开发大型程序,当程序的规模达到一定的程度时,程序员很难控制程序的复杂性。
c++的特点
c++继承了c的优点,并有自己的特点,主要有:
1、全面兼容c,c的许多代码不经修改就可以为cpp所用,用c编写的库函数和实用软件可以用于cpp。
2、用c++编写的程序可读性更好,代码结构更为合理,可直接在程序中映射问题空间结构。
3、生成代码的质量高,运行效率高。
4、从开发时间、费用到形成软件的可重用性、可扩充性、可维护性和可靠性等方面有了很大提高,使得大中型的程序开发项目变得容易得多。
5、支持面向对象的机制,可方便的构造出模拟现实问题的实体和操作。
c++的程序特征
例1.1 输出一行字符:“this is a c++ program.”。
程序如下:
#include //包含头文件iostream using namespace std; //使用命名空间std int main( ) { cout<>a>>b; //输入语句 sum=a+b; //赋值语句 cout<<″a+b=″y) z=x; //if语句,如果x>y, 则将x的值赋给z else z=y; //否则,将y的值赋给z return(z); //将z的值返回,通过max带回调用处 } //max函数结束 int main( ) //主函数 { //主函数体开始 int a,b,m; //变量声明 cin>>a>>b; //输入变量a和b的值 m=max(a,b); //调用max函数,将得到的值赋给m cout<<″max=″>a>>b; c=max(a,b); //调用max函数例1.3 给两个数x和y, 求两数中的大者。 cout<<″max=″y) z=x; else z=y; return(z); }
只要在被调用函数的首部的末尾加一个分号,就成为对该函数的函数声明。函数声明的位置应当在函数调用之前。
c++程序的结构特性
一个面向对象的c++程序一般由类的声明和类的使用两大部分组成。
类的使用部分一般由主函数及有关子函数组成。
典型的c++程序结构
#include //类的声明部分 class a{ int x,y,z; …… fun( ){……} …… }; //类的使用部分 int main() { a a; …… a.fun(); return 0; }
在c++程序中,程序设计始终围绕“类”展开。通过声明类,构建了程序所要完成的功能,体现了面向对象程序设计的思想。
c++程序的编辑、编译和运行
c++源程序文件的扩展名为.cpp
可以用多种编译器编辑、编译和运行
c++对c的补充
1、注释与续行
注释符:“/*”和“*/” 或“//” 。
cpp新增了注释语句,它由“//”开始,到行尾结束。
例如:
x = y + z; /*this is a comment */
x = y + z; //this is a comment
续行符:“\”(反斜杠)。作用是当一个语句太长时可以用该符号把它分段写在几行中。 例:
cout << ‘\n’ << “x=” << x << “y=” << y << “z=” << z\ << “u=” << u << “v\ =” << v << “w=” << w <> i; cout << f;
cout和cin分别是c++的标准输出流和输入流。cpp支持重定向,但一般cout指的是屏幕, cin指的是键盘。
操作符“”除了具有c语言中定义的左移和右移的功能外,在这里符号“”则是将标准输入流的数据赋给右方的变量。
例1.4 一个完整的c++程序
#include int main() { char name[20]; cout name; cout <>,cout和<> a >> b >> c;
换行符:‘\n’或endl
如:cout << “x=” << x << endl; cout << “x=” << x << ‘\n’;
使用cout和cin时,也可以对输入和输出的格式进行控制,比如可用不同的进制方式显示数据,只要设置转换基数的操作符dec、hex和oct即可。
例1.5 操作符dec、 hex和oct的使用
#include void main() { int x=25; cout << hex << x << ' ' << dec << x << ' ' << oct << x << '\n'; }
输出结果为:19 25 31
3、灵活的变量说明
定义变量的位置
在程序中的不同位置采用不同的变量定义方式,决定了该变量具有不同的特点。变量的定义一般可有以下三种位置:
(1) 在函数体内部
在函数体内部定义的变量称为局部变量,这种局部变量只在进入定义它的函数体时起作用,离开该函数体后该变量就消失(被释放),即不再起作用。因此,不同函数体内部可以定义相同名称的变量,而互不干扰。
(2) 形式参数
当定义一个有参函数时,函数名后面括号内的变量,统称为形式参数。
(3) 全局变量
在所有函数体外部定义的变量,其作用范围是整个程序,并在整个程序运行期间有效。
在c语言中,全局变量声明必须在任何函数之前,局部变量必须集中在可执行语句之前。
cpp中的变量声明非常灵活,它允许变量声明与可执行语句在程序中交替出现。
例如
f( ) { int i; i=10; int j; j=25; // … } float fun(int x,int y) { for(int i=0;i<10;i++) { int sum=0; sum=sum+i; cout<<“sum=”
4、结构、联合和枚举名
在c++中,结构名、联合名、枚举名都是类型名。在定义变量时,不必在结构名、联合名或枚举名前冠以struct、union或enum。
例如:
enum boole{false,true}; struct string{ char *string; int length; }; union number{ int i; float f; };
在传统的c中,定义变量时,必须写成:
enum boole done; struct string str; union number x;
但是,在c++中,可以说明为:
boole done; string str; number x;
5、函数原型
c语言建议编程者为程序中的每一个函数建立原型,而cpp要求为每一个函数建立原型,以说明函数的名称、参数类型与个数,以及函数返回值的类型。
其主要目的是让c++编译程序进行类型检查,即形参与实参的类型匹配检查,以及返回值是否与原型相符,以维护程序的正确性。
例如
int sum(int a,int b); //是函数sum的原型
函数原型语法的一般形式为:返回类型 函数名(参数表);
函数原型是一条语句,它必须以分号结束。
例1.6 函数原型的说明
#include void write(char *s); void main() {write(hello,world!);} void write(char *s) {cout<
在程序中,要求一个函数的原型出现在该函数的调用语句之前。
说明:
函数原型的参数表中可不包含参数的名字,而只包含它们的类型。例如:long area(int ,int);
函数定义由函数首部和函数体构成。函数首部和函数原型基本一样,但函数首部中的参数必须给出名字而且不包含结尾的分号。
cpp的参数说明必须放在函数说明后的括号内,不可将函数参数说明放在函数首部和函数体之间。这种方法只在c中成立。
主函数不必进行原型说明,因为它被看成自动说明原型的函数。
原型说明中没有指定返回类型的函数(包括主函数main),cpp默认该函数的返回类型是int
如果一个函数没有返回值,则必须在函数原型中注明返回类型为void,主函数类似处理。
如果函数原型中未注明参数,cpp假定该函数的参数表为空(void)。
6、const修饰符
在c中,习惯使用#define定义常量。
一般格式: #define 宏名 常数
如
#define pi 3.14 ………… s = 2 * pi * r; …………
c++利用const定义正规常数
一般格式:const 数据类型标识符 常数名=常量值;
采用这种方式定义的常量是类型化的,它有地址,可以用指针指向这个值,但不能修改它。
说明:
1、const必须放在被修饰类型符和类型名前面
2、数据类型是一个可选项,用来指定常数值的数据类型,如果省略了该数据类型,那么编译程序认为它是 int 类型。
如:const int a=10; 表示定义了一个初始值为10的整型常量,它在程序中不可改变,但可用于表达式的计算中。
例2.6 #define的不安全性
#include iostream.h main() { int a=1; #define t1 a+a #define t2 t1-t1 cout<但实际的输出是:t2 is 2
const作用与#define相似,但消除了#define的不安全性。
如果用const取代了两个#define,就不会引起这个错误。
#include int main() { int a=1; const t1=a+a; const t2=t1-t1; cout <const可以与指针一起使用
(1)指向常量的指针:一个指向常量的指针变量。
例如:
const char* pc=“abcd”; //声明指向常量的指针 pc[3]=‘x’; //错误
pc=“efgh”; //允许
(2)常指针:把指针本身,而不是它指向的对象声明为常量。
例如:
char* const pc=“abcd”; //常指针 pc[3]=‘x’; //合法 pc=“efgh”; //出错
创建一个常指针,就是创建一个不能移动的固定指针,但是它所指的数据可以改变。例如:
(3)指向常量的常指针:这个指针本身不能改变,它所指向的值也不能改变。
要声明一个指向常量的常指针,二者都要声明为const。
例如:
const char* const pc=“abcd”; //指向常量的常指针 pc[3]=‘x’; //出错 pc=“efgh”; //出错
这个语句的含义是:声明了一个名为pc的指针变量,它是一个指向字符型常量的常指针,用“abcd”的地址初始化该指针。
说明
(1). 如果用const定义的是一个整型常量,关键词int可以省略。所以下面的两语句是等价的
const int bufsize=200;
const bufsize=200;
(2). 常量一旦被建立,在程序的任何地方都不能再更改。
(3). 与#define定义的常量有所不同,const定义的常量可以有自己的数据类型,这样c++的编译程序可以进行更加严格的类型检查,具有良好的编译时的检测性。
(4). 函数参数也可以用const说明,用于保证实参在该函数内部不被改动,大多数c++编译器能对具有const参数的函数进行更好的代码优化。
例如:通过函数i_max求出整型数组a[200]中的最大值,函数原型应该是:int i_max(const int* ptr);
这样做的目的是确保原数组的数据不被破坏,即在函数中对数组元素的操作只许读,而不许写。调用时的格式可以是:i_max(a);
7、void型指针
void 通常表示无值,但将void作为指针的类型时,它却表示不确定的类型。
这种void型指针是一种通用型指针,也就是说任何类型的指针值都可以赋给void类型的指针变量。
例如下面的程序段
void pa; //错误,不能声明void类型的指针变量 void* pc; //正确,可以声明void类型的指针 int i=456; char c=‘a’; pc=&i; pc=&c;
void型指针可以接受任何类型的指针的赋值,但对已获值的void型指针,对它在进行处理,如输出或传递指针值时,则必须进行强制类型转换,否则会出错。
#include main() { void *pc; int i=456; char c='a'; pc=&i; cout<<*(int *)pc<8、内联函数
调用函数时系统要付出一定的开销,用于信息入栈出栈和参数传递等。特别是对于那些函数体较小但调用又较频繁的函数,计算机的开销相对就比较可观。
在c语言中,用宏替换,可解决这个问题。例如,有如下的函数:
add(int x,int y) { return x+y; }
用宏替换时,上面的函数功能可写为:
#define add(x,y) x+y
c++引进了内联函数(inline function)的概念。
宏替换实质上是文字替换。内联函数与一般函数不同的是,在进行程序的编译时,编译器将内联函数的目标代码作拷贝并将其插入到调用内联函数的地方。
例1.7 内联函数的使用
#include iostream.h inline double circle(double r) {return 3.1416*r*r;} int main() { for(int i=1;i<=3;i++) cout<说明:
(1). 内联函数在第一次被调用前必须进行声明或定义,否则编译器将无法知道应该插入什么代码。
(2). c++的内联函数具有与c中的宏定义#define相同的作用和类似机理,但消除了#define的不安全性。
(3). 内联函数体内一般不能有循环语句和开关语句。
(4). 后面类结构中所有在类说明体内定义的函数都是内联函数。
(5). 通常较短的函数才定义为内联函数。
9、带有缺省参数值的函数
在c++中,函数的参数可以有缺省值。
当调用有缺省参数的函数时,如果相应的参数没有给出实参,则自动用相应的缺省参数值作为其实参。
函数的缺省参数,是在函数原型中给定的。
例如:
int init(int x=5, int y=10); init(100,80); //允许 init(25); //允许 init(); //允许
说明:
(1)在函数原型中,所有取缺省值的参数必须出现在不取缺省值的参数的右边。
int fun(int i,int j=5,int k); 错误
int fun(int i,int k,int j=5); 正确
(2)在函数调用时,若某个参数省略,则其后的参数皆应省略而采用缺省值。
init (,20) 错误
例.编写一个带有默认参数的函数,使得在默认情况下显示两个整数的较大者,否则显示两个整数的较小者。
int main() { void showvalue(int x, int y, bool max = true); // 声明函数 int a = 5, b = 10; showvalue(a,b); showvalue(a,b,false); return 0; } void showvalue(int x, int y, bool max = true) // 定义函数 { if(max) cout << “the bigger value is: 10、函数重载
(1) 什么是函数重载
函数重载是指一个函数可以和同一作用域中的其他函数具有相同的名字,但这些同名函数的参数类型、参数个数不同。如:
#include void whatitis(int i) { cout<在本例中定义了两个名称都叫whatitis的函数,但它们的形参类型不同。因此,这两个函数就是重载函数。
(2) 为什么要使用函数重载
在原有c语言中,每个函数必须有其唯一的名称,这样的缺点是所有具有相同功能、而只是函数参数不一样的函数,就必须用一个不同的名称.
而c++中采用了函数重载后,对于具有同一功能的函数,如果只是由于函数参数类型不一样,则可以定义相同名称的函数。
(3) 匹配重载函数的顺序
由于重载函数具有相同的函数名,在进行函数调用时,系统一般按照调用函数时的参数个数、类型和顺序来确定被调用的函数。
具体来说,按以下三个步骤的先后次序找到并调用那个函数:
(1)寻找一个严格的匹配,即:调用与实参的数据类型、个数完全相同的那个函数。
(2)通过内部转换寻求一个匹配,即:通过(1)的方法没有找到相匹配的函数时,则由c++系统对实参的数据类型进行内部转换,转换完毕后,如果有匹配的函数存在,则执行该函数。
(3)通过用户定义的转换寻求一个匹配,若能查出有唯一的一组转换,就调用那个函数。即:在函数调用处由程序员对实参进行强制类型转换,以此作为查找相匹配的函数的依据。
例1.8 重载例子
#include void print(double d) { cout<例 重载例子
编写一个程序,用来求两个整数或3个整数中的最大数。如果输入两个整数,程序就输出这两个整数中的最大数,如果输入3个整数,程序就输出这3个整数中的最大数。
#include using namespace std; int main( ) { int max(int a,int b,int c); //函数声明 int max(int a,int b); //函数声明 int a=8, b=-12, c=27; cout<b) return a; else return b; }
(4) 定义重载函数时的注意事项
重载函数间不能只是函数的返回值不同,应至少在形参的个数、参数类型或参数顺序上有所不同。
如:
void myfun(int i) {………………} int myfun(int i) {………………} // 这种重载是错误的
应使所有的重载函数的功能相同。如果让重载函数完成不同的功能,会破坏程序的可读性。
(5) 函数模板
1) 函数模板 (function template):
建立一个通用函数,其函数类型和形参类型不具体指定,而是一个虚拟类型。
2) 应用情况:
凡是函数体相同的函数都可以用这个模板来代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现了不同函数的功能。
3) 一般形式:
- template // 模板头 通用函数定义
- template // 模板头 通用函数定义
- template // 多个参数 通用函数定义
说明:class与typename可以通用
#include using namespace std; template // 模板声明,其中t为类型参数 t max(t a, t b) // 定义一个通用函数, t作为虚拟的类型名 { if(b>a) return b; else return a; } //template t max(t a, t b) //{ //… //} int main( ) { int i1=111, i2=222, i; double d1=12.34, d2=56.78,d; i=max(i1,i2); // 调用模板函数,此时t被 int 取代 d=max(d1,d2,d3); // 调用模板函数,此时t被 double 取代 cout<a) a=c; return a; }
2) 与重载函数比较:用函数模板比函数重载更方便,程序更简洁。但应注意它只适用于:函数的参数个数相同而类型不同,且函数体相同的情况。如果参数的个数不同,则不能用函数模板;
3) main函数不能定义为模板函数。
11. 作用域标示符::
通常情况下,如果有两个同名变量,一个是全局的,另一个是局部的,那么局部变量在其作用域内具有较高的优先权。
下面的例子说明了这个问题。
#include iostream.h int avar=10; main( ) { int avar; avar=25; cout<如果希望在局部变量的作用域内使用同名的全局变量,可以在全局变量加上“::”,此时::avar代表全局变量avar
#include int avar=10; main() { int avar; avar=25; cout<12、无名联合
无名联合是c++中的一种特殊联合,可以声明一组无标记名共享同一段内存地址的数据项。如:
union{ int i; float f; }
在此无名联合中,声明了变量i和f具有相同的存储地址。无名联合可通过使用其中数据项名字直接存取,例如可以直接使用上面的变量i或f,如:i=20;
13、强制类型转换
在c中数据类型转换的一般形式:(数据类型标识符)表达式
int i=10; float x=(float) i;
c++支持这样的格式,还提供了一种更为方便的函数调用方法,即将类型名作为函数名使用,使得类型转换的执行看起来好像调用了一个函数。形式为:数据类型标识符 (表达式)
int i=10; float x=float(i);
以上两种方法c++都接受,但推荐使用后一种方式。
14、动态内存分配
作为对c语言中malloc和free的替换,c++引进了new和delete操作符。它们的功能是实现内存的动态分配和释放。
动态分配new的一般形式是:
指针变量=new 数据类型;
指针变量=new 数据类型(初始值);
int *a, *b; a=new int; b=new int(10);
释放由new操作动态分配的内存时,用delete操作。
它的一般形式是:delete 指针变量;
delete a; delete b;
例1.9 操作符new和delete的使用
#include main() { int *p; // 声明一个整型指针变量p p=new int; // 动态分配一个存放int型数据的内存空间,并将首地址赋给p *p=10; coutage=23; cout<<\n<
name<< < age; delete p; return 0; }
与c的内存动态分配和释放操作(malloc和free)相比,c++提供的动态分配有以下优点
(1) new和delete 操作自动计算需要分配和释放类型的长度。这不但省去了用sizeof计算长度的步骤,更主要的是避免 了内存分配和释放时因长度出错带来的严重后果;
(2) new操作自动返回需分配类型的指针, 无需使用强制类型转换;
(3) new操作能初始化所分配的类型变量。
(4) new和delete都能可以被重载,允许建立自定义的内存管理法。
对使用new和delete的几点说明:
(1)用new分配的空间,使用结束后应该用delete显示的释放,否则这部分空间将不能回收而变成死空间。
(2)使用new动态分配内存时,如果没有足够的内存满足分配要求, new将返回空指针(null)。因此通常要对内存的动态分配是否成功进行检查。
例1.11 对内存的动态分配是否成功进行检查
#include main() { int * p; p=new int; if(!p){ cout<(3) 使用new可以为数组动态分配内存空间这是需要在类型后面缀上数组大小。其语法形式为:
指针变量=new 类型名 [下标表达式];
如:int *pi=new int[2][3][4];
其中第一维的界值可以是任何合法的表达式,如:int i=3; int *pi=new int[ i ][2][3];
例如:int *pi=new int[10];
这时new为具有10个元素的整型数组分配了内存空间,并将首地址赋给了指针pi。
使用new为多维数组分配空间时,必须提供所有维的大小,
(4) 释放动态分配的数组存储区时,可使用delete运算符,其语法形式为:delete [ ]指针变量;
无须指出空间的大小,但老版本的cpp要求在delete的方括号中标出数字,以告诉cpp要释放多少个元素所占的空间。例如:delete []pi; delete [10]pi;
(5) new可在为简单变量分配内存空间的同时,进行初始化。这时的语法形式为:指针变量=new 类型名(初始值列表)
例 1.12 new为简单变量分配内存空间的同时,进行初始化
#include int main() { int *p; p=new int(99); // 动态分配内存,并将99作为初始值赋给它 if (!p) { cout<例 1.13 给数组分配内存空间的例子。
#include main() { double *s; s=new double[10]; if(!s){ cout<15. 引用
(1) 引用的概念
引用就是某一变量(目标)的一个别名,这样对引用的操作就是对目标的操作。
引用的声明方法: 类型标识符 &引用名=目标变量名;
int a; int &ra=a; //定义引用ra,它是变量a的引用,即别名
说明:
(1) &在此不是求地址运算,而是起标识作用。
(2) 类型标识符是指目标变量的类型。
(3)声明引用时,必须同时对其进行初始化。
(4)引用声明完毕后,相当于目标变量名有两个名称。
(5)声明一个引用,不是新定义了一个变量,系统并不给引用分配存储单元。
例1.15 引用的使用
#include void main() { int i; int &j=i; i=30; cout<结果:
i=30 j=30 i=80 j=80 address of oxfff4 address of oxfff4
例1.16 使用引用可以简化程序
#include main() { int i=15; int* iptr=&i; int & rptr=i; cout<< i is 运行结果:
i is 15 *iptr is 15 rptr is 15 after changing i to 29: i is 29 *iptr is 29 rptr is 29
(2) 引用的使用
(1)引用名可以是任何合法的变量名。除了用作函数的参数或返回类型外,在声明时,必须立即对它进行初始化,不能声明完后再赋值。
int i; int &j; j=i;
(2)引用不能重新赋值,不能再把该引用名作为其他变量名的别名,任何对该引用的赋值就是该引用对应的目标变量名的赋值。对引用求地址,就是对目标变量求地址。
int i=5; int &j1=i; int &j2=j1;
int num=50; int & ref=num; int *p=&ref;
(3)由于指针变量也是变量,所以,可以声明一个指针变量的引用。方法是: 类型标识符 *&引用名=指针变量名;
#include void main() { int *a; //定义指针变量a int *&p=a; //定义引用p,初始化为指针变量a,所以p是a的引用(别名) int b=10; p=&b; //等价于a=&b,即将变量b的地址赋给a。 cout<<*a<endl; }
(4)引用是对某一变量或目标对象的引用,它本身不是一种数据类型,因此引用本身不占存储单元,这样,就不能声明引用的引用,也不能定义引用的指针。
int a; int & & ra=a; //错误 int &*p=&ra; //错误
(5)不能建立数组的引用,因为数组是一个由若干个元素所组成的集合,所以就无法建立一个数组的别名。
(6)不能建立空指针的引用
int &rp=null; //错误
(7)也不能建立空类型void的引用,因为尽管在c++语言中有void数据类型,但没有任何一个变量或常量属于void类型。
void &ra=3; //错误
(8) 尽管引用运算符与地址操作符使用相同的的符号,但时不一样的。引用仅在声明时带有引用运算符&,以后就像普通变量一样使用,不能再带&。其他场合使用的&都是地址操作符。
int j=5; int& i=j; // 声明引用i, &为引用运算符 i=123; // 使用引用i,不带引用运算符 int *pi=&i; // 在此, &为地址操作符 cout<<π // 在此, &为地址操作符
(3) 用引用作为函数的参数
一个函数的参数也可定义成引用的形式
void swap(int &p1, int &p2) //形参p1, p2都是引用 { int p; p=p1; p1=p2; p2=p; }
在主调函数的调用点处,直接以变量作为实参进行调用即可,不需要实参变量有任何的特殊要求。
swap(a,b); //直接以a和b作为实参调用swap函数
例1.17 采用指针参数的例子
#include void swap(int *m, int *n) { int temp; temp=*m; *m= *n; *n=temp; } main() { int a=5, b=10; cout<运行结果:
a=5 b=10 a=10 b=5
例1.18 采用“引用参数”传递函数参数
#include void swap(int& m, int& n) { int temp; temp=m; m=n; n=temp; } main() { int a=5, b=10; cout<运行结果:
a=5 b=10 a=10 b=5
(4) 用引用返回函数值
函数可以返回一个引用,将函数说明为返回一个引用的主要目的是:为了将函数用在赋值运算符的左边。
要以引用返回函数值,则函数定义时要按以下格式:
类型标识符 &函数名(形参列表及类型说明)
{函数体}
说明
以引用返回函数值,定义函数时需要在函数名前加&
用引用返回一个函数值的最大好处是,在内存中不产生被返回值的副本。
例1.19 返回引用的函数
#include int a[]={1, 3, 5, 7, 9}; int& index(int); // 声明返回引用的函数 void main() { cout<2)<number; for (i=2;iarray(i)=array(i-2)+array(i-1); cout<a>>b; swap(&a,&b); //必须以变量a和b的地址作为实参 couta[i]; max_min(a,10,ma,mi); //调用函数max_min cout例 以下程序中定义了一个普通的函数fn1(它用返回值的方法返回函数值),另外一个函数fn2,它以引用的方法返回函数值。
#include float temp; //定义全局变量temp float fn1(float r); //声明函数fn1 float &fn2(float r); //声明函数fn2 float fn1(float r) //定义函数fn1,它以返回值的方法返回函数值 { temp=(float)(r*r*3.14); return temp; } float &fn2(float r) //定义函数fn2,它以引用方式返回函数值 { temp=(float)(r*r*3.14); return temp; } void main() //主函数 { float a=fn1(10.0);//第1种情况,系统生成要返回值的副本(即临时变量) float &b=fn1(10.0);//第2种情况,可能会出错(不同c++系统有不同规定) //不能从被调函数中返回一个临时变量或局部变量的引用 float c=fn2(10.0); //第3种情况,系统不生成返回值的副本 //可以从被调函数中返回一个全局变量的引用 float &d=fn2(10.0); //第4种情况,系统不生成返回值的副本 //可以从被调函数中返回一个全局变量的引用 cout<
一个返回引用的函数值作为赋值表达式的左值
一般情况下,赋值表达式的左边只能是变量名,即被赋
值的对象必须是变量,只有变量才能被赋值,常量或表达式不能被赋值,但如果一个函数的返回值是引用时,赋值号的左边可以是该函数的调用。
例2-26 测试用返回引用的函数值作为赋值表达式的左值。
#include int &put(int n); int vals[10]; int error=-1; void main() { put(0)=10; //以put(0)函数值作为左值, 等价于vals[0]=10; put(9)=20; //以put(9)函数值作为左值, 等价于 vals[9]=10; cout<0]; cout=0 && n<=9 ) return vals[n]; else{ cout<<”subscript error”; return error; } }
用const限定引用
声明方式:const 类型标识符 &引用名=目标变量名;
用这种方式声明的引用,不能通过引用对目标变量的值进行修改,从而使引用的目标成为const,达到了引用的安全性。
例2-27
#include “iostream.h” double &fn(const double &pd) { static double ad=32; ad+=pd; cout程序运行的结果
100 132 200 332
引用总结
(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大对象的传递效率和空间不如意的问题。
(2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作,程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
课后练习题目
#include int &max(int &num1,int &num2); // 返回一个较大值 int &min(int &num1,int &num2); // 返回一个较小值 main() { int num1, num2; coutnum1; coutnum2; max(num1,num2)=0; cout<<\nafter putting zero in largest, the numbers are; cout<<\n< and <\n; cout<<\nnow, please enter two more numbers.\n; coutnum1; coutnum2; min(num1, num2)=0; cout<<\nafter putting zero in smallest the numbers are; cout<<\n< and num2)?num1:num2; } int &min(int &num1,int &num2) { return (num1
苹果还是三星?浅谈智能手表的发展方向
基于EL7516的高电流白光LED驱动器设计
电蜂工厂Mini Fakra连接器插头的基本性能
高通与苹果将专利许可协议延长两年
微公子车载充电器革新车充时代
C语言和C++的特点与用法详细说明
半导体市场前景看好 三季度迎高峰
魅族、金立、联想纷纷掉队 5G班车转瞬即逝
地物光谱匹配模型研究
如何用最快的速度学会Dlib人脸识别开发?
一文详解C语言指针变量
e络盟micro:bit产量突破500万台,持续助力Micro:bit教育基金会推广最新款micro:bit
“刀片电池”横空出世,磷酸铁锂电池或迎来拐点
IBM将从Software AG 收购 StreamSets 和 webMethods平台
许可链和公链在区块链中的作用是什么
爆炸门之后更自信 三星S8发布时间确定 网友却说爱你不容易!
中国电信发挥“5G+云+AI”云网一体优势首家实现“一省一池”的云服务
iPhone8什么时候上市最新消息:iPhone8真机曝光已经开始量产,四大新功能不可不知,价格1000美元起
宏景智驾与华安证券达成全面合作
大数据时代下的三种存储架构