第三讲C++对C的扩充2.docx

上传人:b****6 文档编号:8013769 上传时间:2023-01-27 格式:DOCX 页数:15 大小:37.78KB
下载 相关 举报
第三讲C++对C的扩充2.docx_第1页
第1页 / 共15页
第三讲C++对C的扩充2.docx_第2页
第2页 / 共15页
第三讲C++对C的扩充2.docx_第3页
第3页 / 共15页
第三讲C++对C的扩充2.docx_第4页
第4页 / 共15页
第三讲C++对C的扩充2.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

第三讲C++对C的扩充2.docx

《第三讲C++对C的扩充2.docx》由会员分享,可在线阅读,更多相关《第三讲C++对C的扩充2.docx(15页珍藏版)》请在冰豆网上搜索。

第三讲C++对C的扩充2.docx

第三讲C++对C的扩充2

第三讲:

C++对C的扩充

(2)

本讲基本要求

    掌握:

函数默认参数的设置方法;变量引用的方法及作用;字符串变量的定义、应用;。

    理解:

作用域运算符的作用;new、delete运算符。

    重点、难点:

变量引用的方法及作用。

六、有默认参数的函数

   一般情况下:

在函数调用时形参从实参那里取得值,因此实参的个数应与形参相同。

但是有时多次调用同一函数时用的是同样的实参值,C++提供简单的处理办法,给形参一个默认值,这样形参就不必一定要从实参取值了。

如有一函数声明:

floatarea(floatr=6.5);

   指定r的默认值为6.5,如果在调用此函数时,确认r的值为6.5,则可以不必给出实参的值,

         如:

area();//相当于area(6.5);

   可以看到,在调用有默认参数的函数时,实参的个数可以与形参不同,实参未给定的,从形参的默认值得到值。

利用这一特性,可以使函数的使用更加灵活。

在使用带有默认参数的函数时有两点要注意:

   

(1)如果函数的定义在函数调用之前,则应在函数定义中给出默认值。

如果函数的定义在函数调用之后,则在函数调用之前需要有函数声明,此时必须在函数声明中给出默认值,在函数定义时可以不给出默认值。

也就是说必须在函数调用之前将默认值的信息通知编译系统。

由于编译是从上到下逐行进行的,如果在函数调用之前未得到默认值信息,在编译到函数调用时,就会认为实参个数与形参个数不匹配而报错。

   如果在声明函数时已对形参给出了默认值,而在定义函数时又对形参给出默认值,有的编译系统会给出“重复指定默认值”的报错信息,有的编译系统对此不报错,甚至允许在声明时和定义时给出的默认值不同,此时编译系统以先遇到的为准。

由于函数声明在函数定义之前,因此以声明时给出的默认值为准,而忽略定义函数时给出的默认值。

   

(2)一个函数不能既作为重载函数,又作为有默认参数的函数。

因为当调用函数时如果少写一个参数,系统无法判定是利用重载函数还是利用默认参数的函数,会出现二义性,系统无法执行。

七、变量的引用:

引用(reference)是C++对C的一个重要扩充。

1.引用的概念

  在c++中,变量的“引用”就是变量的别名,因此引用又称为别名(alias)。

建立“引用”的作用是为一个变量起另一个名字,以便在需要时可以方便、间接地引用该变量,这就是引用名称的由来。

对一个变量的“引用”的所有操作,实际上都是对其所代表的(原来的)变量的操作。

假如有一个变量a,想给它起一个别名b,

可以这样写:

   inta;

   int&b=a;//声明b是一个整型变量的引用变量,它被初始化为a

注意:

   1、在上述声明中,&是“引用声明符”,此时它并不代表地址。

不要理解为“把a的值赋给b的地址”。

对变量声明一个引用,并不另开辟内存单元,b和a都代表同一变量单元。

在声明一个引用时,必须同时使之初始化,即声明它代表哪一个变量。

  2、由于引用不是独立的变量,编译系统不给它单独分配存储单元,因此在建立引用时只有声明,没有定义,只是声明它和原有的某一变量的关系。

  3、声明一个变量的引用后,在本函数执行期间,该引用一直与其代表的变量相联系,不能再作为其他变量的别名。

下面的用法不对:

    inta1,a2;

    int&b=a1;//使b成为变量a1的引用(别名)

    int&b=a2;//又企图使b成为变量a2的引用(别名)是不行的

2.引用的简单使用

  通过下面的例子可以了解引用的简单使用。

例9了解引用和变量的关系。

#include

usingnamespacestd;

intmain()

 {inta=10;

  int&b=a;//声明b是a的引用

  a=a*a;  //a的值变化了,b的值也应一起变化

  cout<

  b=b/5;  //b的值变化了,a的值也应一起变化

  cout<

  return0;

 }

  a的值开始为1O,b是a的引用,它的值当然也应该是10,当a的值变为100(a。

a的值)时,b的值也随之变为100,在输出a和b的值后,b的值变为20,显然a的值也应为20。

运行记录如下:

  100100

  2020

3.关于引用的简单说明

  

(1)引用并不是一种独立的数据类型,它必须与某一种类型的数据相联系。

声明引用时必须指定它代表的是哪个变量,即对它初始化。

  

(2)引用与其所代表的变量共享同一内存单元,系统并不为引用另外分配存储空间。

实际上,编译系统使引用和其代表的变量具有相同的地址。

  (3)当看到&a这样的形式时,怎样区别是声明引用变量还是取地址的操作呢?

请记住,当及a的前面有类型符时(如int &a),它必然是对引用的声明;如果前面没有类型符(如p=&a),此时的&是取地址运算符。

  (4)对引用的初始化,可以用一个变量名,也可以用另一个引用。

  (5)引用在初始化后不能再被重新声明为另一变量的别名。

  实际上,在C++程序中很少使用独立变量的引用,如果要使用某一个变量,就直接使用它的原名,没有必要故意使用它的别名。

前面举的例子只是为了说明引用的特征和基本的用法。

那么有了变量名,为什么还需要一个别名呢?

4.将引用作为函数参数

  C++之所以增加“引用”,主要是利用它作为函数参数,以扩充函数传递数据的功能。

  在C语言中,函数的参数传递有以下两种情况。

  

(1)将变量名作为实参。

这时传给形参的是变量的值。

传递是单向的,在执行函数期间形参值发生变化并不传回给实参,因为在调用函数时,形参和实参不是同一个存储单元。

下面的程序无法实现两个变量的值互换。

例10无法实现两个变量的值互换的程序。

#include

usingnamespacestd;

voidswap(inta,intb)

  {inttemp;

   temp=a;

   a=b;

   b=temp;//实现a和b的值互换

  }

intmain()

 { inti=3,j=5;

  swap(i,j);

  cout<

  return0;

 }

  输出i和j的值仍为3和5。

见图2,图2(a)表示调用函数时的数据传递,图2(b)是执行swap函数体后的情况,a和b值的改变不会影响i和j的值。

      

图2:

i、j值未交换,  图3:

i、j值交换,

  

(2)传递变量的指针。

为了解决上面这个问题,在C程序中可以用传递变量地址的方法。

使形参得到一个变量的地址,这时形参指针变量指向实参变量单元。

例11使用指针变量作形参,实现两个变量的值互换。

#include

usingnamespacestd;

voidswap(int*p1,int*p2)

  { inttemp;

   temp=*p1;

   *p1=*p2;

   *p2=temp;

  }

intmain()

 { inti=3,j=5;

  swap(&i,&j);

  cout<

  return0;

  }

  (3)传送变量的别名。

C++把变量的引用作为函数形参,就弥补了上面的不足。

这就是向函数传递数据的第三种方法,即传送变量的别名。

例12利用“引用形参”实现两个变量的值互换。

#include

usingnamespacestd;

voidswap(int&a,int&b)

  {inttemp;

   temp=a;

   a=b;

   b=temp;

  }

intmain()

 { inti=3,j=5;

  swap(i,j);

  cout<<"i="<

  return0;

 }

输出结果为i=5j=3

 

图4:

别名实现变量的交换

  

  分析使用引用和使用指针变量作函数形参有什么不同?

可以发现:

  ①不必在swap函数中设立指针变量,指针变量要另外开辟内存单元,其内容是地址。

而引用不是一个独立的变量,不单独占内存单元,在本例中其值为一整数。

  ②在main函数中调用swap函数时实参不必在变量名前加&以表示地址。

这种传递方式相当于Pascal语言中的“变量形参”,系统传送的是实参的地址而不是实参的值。

  ③使用指针变量时,为了表示指针变量所指向的变量,必须使用指针运算符。

(如例11程序内swap函数中的。

pl,*p2),而使用引用时,引用就代表该变量,不必使用指针运算符*(见例12程序内swap函数)。

对比例11和例12中的swap函数,可以发现例12中的swap函数比例11中的swap函数简单。

  ④用引用能完成的工作,用指针也能完成。

但引用比指针的使用直观、方便,直截了当,不必“兜圈子”,容易理解。

有些过去只能用指针来处理的问题,现在可以用引用来代替,从而降低了程序设计的难度。

5.对引用的进一步说明

  

(1)不能建立void类型的引用,如:

void&a=9;//错误

    因为任何实际存在的变量都是属于非void类型的,void的含义是无类型或空类型,void只是在语法上相当于一个类型而已。

  

(2)不能建立引用的数组。

    如:

  charc[6]="hello";

       char&rc[6]=c;//错误

    企图建立一个包含6个元素的引用的数组,这样是不行的,数组名C只代表数组首元素的地址,本身并不是一个占有存储空间的变量。

  (3)可以将变量的引用的地址赋给一个指针,此时指针指向的是原来的变量。

    如:

inta=3; //定义a是整型变量

      int&b=a;//声明b是整型变量的别名

      int*P=&b;//指针变量p指向变量a的引用b,相当于指向a,合法

  相当于p指向变量a,其作用与下面一行相同,

     即:

int*p=&a;

  如果输出*p的值,就是b的值,也就是a的值。

但是不能定义指向引用类型的指针变量,不能写成:

        int&*p=&a;//企图定义指向引用类型的指针变量P,错误

  由于引用不是一种独立的数据类型,因此不能建立指向引用类型的指针变量。

  (4)可以建立指针变量的引用。

    如:

inti=5;  //定义整型变量i,初值为5

      int*p=&i  //定义指针变量P,指向i

      int*&pt=p;//pt是一个指向整型变量的指针变量的引用,初始化为p

  从定义的形式可以看出,&pt表示pt是一个变量的引用,它代表一个int,类型的数据对象(即指针变量),如果输出。

pt的值,就是*p的值5。

  (5)可以用const对引用加以限定,不允许改变该引用的值。

    如:

inti=5;    //定义整型变量i,初值为5

      constint&a=i;//声明常引用,不允许改变a的值

      a=3;      //企图改变引用a的值,错误

  但是它并不阻止改变引用所代表的变量的值,如

    i=3;//合法  此时输出i和a的值都是3。

  这一特征在使用引用作为函数形参时是有用的,因为有时希望保护形参的值不被改变,在第3章中将会看到它的应用。

  (6)可以用常量或表达式对引用进行初始化,但此时必须用const作声明。

    如:

inti=5;

      const&a=i+3;//合法

  此时编译系统是这样处理的:

生成一个临时变量,用来存放该表达式的值,引用是该临时变量的别名。

系统将"const=&a=i+3"转换为:

    inttemp=i+3;//先将表达式的值存放在临时变量temp中

    constint&a=temp;//声明a是temp的别名

 注意:

此时如果输出引用a的值,将是3而不是3.1415926。

因为从根本来说,只能对变量建立引用。

如果在上面声明引用时不用const,则会发生错误。

    doubled=3.1415926;//d是double类型变量

     int&a=d;       //未加const,错误

  为什么呢?

若允许这样做的话,如果修改了引用a的值(例如a=6.28;),则临时变量temp的值也变为6,即修改了临时变量temp的值,但不能修改变量d的值,这往往不是用户所希望的,即存在二义性。

与其允许修改引用的值而不能实现用户的目的,还不如不允许修改引用的值。

这就是c++规定对这类引用必须加const的原因。

  C++提供的引用机制是非常有用的,尤其用作函数参数时,比用指针简单、易于理解,而且可以减少出错机会,提高程序的执行效率,在许多情况下能代替指针的操作。

在本书的第3章和第4章中会有具体的使用例子。

八、内置函数

  调用函数时需要一定的时间,如果有的函数需要频繁使用,则累计所用时间会很长,从而降低程序的执行效率,C++提供一种提高效率的方法,即在编译时将所调用函数的代码嵌入到主函数中。

这种嵌入到主函数中的函数称为内置函数(inlinefunction),又称内嵌函数。

在有些书中把它译成内联函数。

  指定内置函数的方法很简单,只须在函数首行的左端加一个关键字inline即可。

例13将函数指定为内置函数。

#include

usingnamespacestd;

inlineintmax(inta,intb,intc)//这是一个内置函数,求3个整数中的最大者

{ if(b>a)a=b;

  if(c>a)a=c;

  returna;

}

intmain()

 {inti=7,j=10,k=25,m;

  m=max(i,j,k);

  cout<<"max="<

  return0;

}

  由于在定义函数时指定它为内置函数,因此编译系统在遇到函数调用nmax(i,j,k)时,就用max函数体的代码代替max(i,j,k),同时将实参代替形参。

这样,m=max(i,j,k)就被置换成

a=i;b=j;c=k;

if(b>a)a=b;

if(c>a)a=c;

m=a;

  内置函数与用#define命令实现的带参宏定义有些相似,但不完全相同。

宏定义是在编译前由预处理程序对其预处理的,它只作简单的字符置换而不作语法检查,往往会出现意想不到的错误。

例14用带参宏定义实现求平方值,

#include

usingnamespacestd;

#definepower(x)x*x

intmain()

 {cout<

(2)<

  cout<

  return0;

 }

本来程序编写者希望两个cout语句都输出2的平方值,但运行结果却是:

    4(输出power(g)的值)

    3(输出power(1+1)的值)

  第2个结果显然不是程序设计者所希望的,原因是在进行宏替换时只是简单地将字符“1+l”取代x,因此power(1+1)被置换为1+1*l+1,结果为3。

  如果不用#define而用内置函数,也可以达到同样的目的,但避免了上面的副作用。

例14程序可改为:

例15用内置函数实现求平方值。

#inclde

useingnamespacestd;

inlineintpower(intx)//改用内置函数

 {  returnx*x;}

 intmain()

  {cout<

(2)<

   cout<

    returnO;

  }

运行结果是

  4(输出power

(2)的值)

  4(输出power(1+1)的值)

  可以看到:

    1、用带参宏定义和内置函数都可以实行置换,但具体的做法不同,用内置函数可以达到用#define宏置换的门的,但不会出现带参宏定义的副作用。

    2、使用内置函数可以节省运行时间,但却增加了目标程序的长度。

九、作用域运算符

  每一个变量都有其确有效的作用域,只能在变量的作用域内使用该变量,不能直接使用其他作用域中的变量。

见例6。

例16局部变量和全局变量同名。

#include

usingnamespacestd;

  floata=13.5;//全局变量a

  intmain()

  {  inta=5; //主函数内变量a 

    cout<

    cout<<:

:

a<

    return0;  }

“:

:

”a表示全局作用域中的变量a。

请注意:

不能用“:

:

”访问函数中的局部变量。

十、字符串变量

  除了可以使用字符数组处理字符串外,C++还提供了一种更方便的方法—用字符串类型(string类型)定义字符串变量。

  实际上,string并不是C++语言本身具有的基本类型(而char,int,float,double等是C++本身提供的基本类型),它是在c++标准库中声明的一个字符串类,用这种类可以定义对象。

1.定义字符串变量

  和其他类型变量一样,字符串变量必须先定义后使用,定义字符串变量要用类名strmg。

如:

    stringstringl;    //定义stringl为字符串变量

    stringstring2="China";//定义string2同时对其初始化

  可以看出,这和定义char,int,float,double等类型变量的方法是类似的。

应当注意:

要使用string类的功能时,必须在本文件的开头将c++标准库中的“string”头文件包含进来,即应加上#include//注意头文件名不是"string.h这一点是与定义基本数据类型变量所不同的。

2.对字符串变量的赋值

  在定义了字符串变量后,可以用赋值语句对它赋以一个字符串常量,

    如:

    string1="Canada";

而用字符数组时是不能像下面这样做的

charstr[10];

str="Hello!

";//错误

  既可以用字符串常量给字符串变量赋值,也可以用一个字符串变量给另一个字符串变量赋值。

    string2=stringl;//假设string2.和stringl均已定义为字符串变量

可以对字符串变量中某一字符进行操作,如

    stringword="Then";//定义并初始化字符串变量word

    word[2]='a';    //修改序号为2的字符,修改后word的值为"Than"

  前面已说明,字符串常量以“\o”作为结束符,但将字符串常量存放到字符串变量中时,只存放字符串本身而不包括“\o”。

因此字符串变量word中的字符为"Than”(共4个字符)而不是"Than"再加“\0”。

3.字符串变量的输入输出

  可以在输入输出语句中用字符串变量名输入输出字符串,如

    cin>>string1;//从键盘输入一个字符串给字符串变量stfingl

    cout<

4.字符串变量的运算

  在用字符数组存放字符串时,字符串的运算要用字符串函数,如strcat(连接),strcmp(比较),strcpy(复制),而对stung类对象,可以不用这些函数,而直接用简单的运算符。

(1)用赋值运算符实现字符串复制

  stringl=string2;其作用与“strcpy(string1,string2);”相同。

(2)用加法运算符实现字符串连接

  stringstring1="C++";//定义string[并赋初值

  stringstring2="Language";//定义string2并赋初值

  stnngl=string1十sane2;//连接string1和string2

  连接后string1为"C++Language"。

(3)用关系运算符实现字符串比较

  可以直接用==(等于)、,(大于)、<(小于)、!

=(不等于)、>=(大于或等于)、<=(小于或等于)等关系运算符来进行字符串的比较。

5.字符串数组

  不仅可以用string定义字符串变量,也可以用string定义字符串数组。

    stringname[5];//定义一个字符串数组,它包含5个字符串元素

    stringname[5]={"Zhang","Li","Fun","Wang","Tan"};//定义一个字符中数组并初始化此时name数组的状况如图5所示。

图5

可以看到:

  

(1)在一个字符串数组中包含若干个(今为5个)元素,每个元素相当于—个字符串变量。

  

(2)并不要求每个字符串元素具有相同的K度,即使对同一个元素而言,它的长度也是可以变化的,当向某一个元素重新赋值时,其长度就可能发生变化,,

  (3)在字符串数组的每一个元素中存放一个字符串,而不是一个字符,这是字符串数组与字符数组的区别。

如果用字符数组存放字符串,一个元素只能存放一个字符,用一个一维字符数组存放一个字符申。

  (4)每一个字符中元素中只包含字符串本身的字符而不包括"\0"。

可见用字符串数组存放字符串以及对字符串进行处理是很方便的,使用户感到更加直观,简化了操作,提高了效率。

例17输入3个字符串,要求按字母由小到大顺序输出。

  对于将3个整数按由小到大顺序输出,是很容易处理的。

可以按照同样的算法将3个字符串按由小到大顺序输出。

程序如下:

#include

#include

usingnamespacestd;

intmain()

 { stringstring1,string2,string3,temp;

  cout<<"pleaseinputthreestrings:

";//这是对用户输入的提示

  cin>>string1>>string2>>string3;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 工作总结汇报

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1