初级C系语言入门到精通_第1页
初级C系语言入门到精通_第2页
初级C系语言入门到精通_第3页
初级C系语言入门到精通_第4页
初级C系语言入门到精通_第5页
已阅读5页,还剩27页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、分支结构程序分支结构程序在C语言中表示条件,一般用关系表达式或逻辑表达式,实现分支结构用if语句或switch语句。关系运算及其表达式· 所谓“关系运算”实际上就是“比较运算”,即将两个数据进行比较,判定两个数据是否符合给定的关系。· 例如,“a > b”中的“>”表示一个大于关系运算。如果a的值是5,b的值是3,则大于关系运算“>”的结果为“真”,即条件成立;如果a的值是2,b的值是3,则大于关系运算“>”的结果为“假”,即条件不成立。关系表达式· 关系表达式的概念· 所谓关系表达式是指,用关系运算符将两个表达式连接起来,进行关

2、系运算的式子。· 例如,下面的关系表达式都是合法的:· a>b,a+b>c-d,(a=3)<=(b=5),'a'>='b',(a>b)= =(b>c)· 关系表达式的值逻辑值(非“真”即“假”)· 由于语言没有逻辑型数据,所以用整数“”表示“逻辑真”,用整数“”表示“逻辑假”。示例假设num1=3,num2=4,num3=5,则: (1)num1>num2的值=0。 (2)(num1>num2)!=num3的值=1。 (3)num1<num2<num3的值=1。

3、思考题:任意改变num1或num2的值,会影响整个表达式的值吗?为什么? (4)(num1<num2)+num3的值=6,因为num1<num2的值=1,1+5=6。if语句· 用if语句可以构成分支结构。它根据给定的条件进行判断,以决定执行某个分支程序段。语言的if语句有三种基本形式· 基本形式:if · 第二种形式为: if-else · 第三种形式为if-else-if形式 基本形式:if 其语义是:如果表达式的值为真,则执行其后的语句, 否则不执行该语句。注意:表达式必须在if后面的一对()中。 示例if-else l 如果表达式的值

4、为非0(TURE)即真, 则执行语句1, 执行完语句1从语句2后开始继续向下执行; 如果表达式的值为0(FALSE)即假, 则跳过语句1而执行语句2。注意:else是当if条件不成立的时候执行下面的语句,所以else后面没有表达式。 示例if-else-if形式 示例注意问题 · 在三种形式的if语句中,在if关键字之后均为表达式。 · 在if语句中,条件判断表达式必须用括号括起来,在语句之后必须加分号。 · 在if语句的三种形式中,所有的语句应为单个语句,如果要想在满足条件时执行一组(多个)语句,则必须把这一组语句用括起来组成一个复合语句。 if语句的嵌套 &#

5、183; 当if语句中的执行语句又是if语句时,则构成了if 语句嵌套的情形。 示例条件运算符 · 如果在条件语句中,只执行单个的赋值语句时, 常可使用条件表达式来实现。不但使程序简洁,也提高了运行效率。 · 由条件运算符组成条件表达式的一般形式为:· 表达式1? 表达式2: 表达式3· 其求值规则为:如果表达式1的值为真,则以表达式2 的值作为条件表达式的值,否则以表达式2的值作为整个条件表达式的值。示例switch语句· C语言提供了switch语句直接处理多分支选择循环 概述 · 循环结构是结构化程序设计中的一个基本组成部分,它

6、所要解决的问题是在某一条件下,要求程序执行相同的语句多次。 · 在c语言中,主要有3种循环结构体: · while结构 · dowhile结构 · for结构 while结构 while语句的语义是:计算表达式的值,当值为真(非0)时, 执行循环体语句。如果表达式为假(0)的是否退出循环体。 执行过程· 判断表达式是否为真,当为真的是否,执行循环体语句,在执行完一次循环体以后,都要判断一下表达式的值,若是真,则再次执行循环体,如此循环一直到表达式的值为假,则直接退出循环体,循环体结束。 示例 dowhile · 这个循环与while循

7、环的不同在于:它先执行循环中的语句,然后再判断表达式是否为真, 如果为真则继续循环;如果为假, 则终止循环。 · 因此, do-while循环至少要执行一次循环语句。 dowhile形式 一般情况下下,while循环和do while循环都可以用力处理同一个问题。但是要注意,while循环可以一次都不执行循环体,然而,do while循环就不一样,程序执行到do while循环结构时,不管条件是否满足,循环体至少要执行一次示例for循环 · for语句的一般格式· for(变量赋初值;循环继续条件;循环变量增值) 循环体语句组;for语句的执行过程(1)求解“变量

8、赋初值”表达式。(2)求解“循环继续条件”表达式。如果其值非0,执行(3);否则,转至(4)。(3)执行循环体语句组,并求解“循环变量增值”表达式,然后转向(2)。(4)执行for语句的下一条语句。初始化表达式· 对于初始化表达式,可以使用逗号表达式设置多个初值 增量表达式· 可以使用逗号表达式嵌套循环 goto语句 · goto语句的一般形式是: · goto 语句标号: break语句 · 当break语句用于do-while、for、while循环语句中时,可使程序终止循环而执行循环后面的语句 continue语句 · cont

9、inue语句的作用是跳过循环本中剩余的语句而强行执行下一次循环 break和continue区别· break语句是跳出并结束整个循环,而不再仅需进行循环条件的判断。· continue语句是结束本次循环,继续进行循环条件的判断来决定是否继续执行循环体语句。数组 一维数组的声明 例如 · int a10; 说明整型数组a,有10个元素。数组中的10个元素都是int类型。· float b10,c20; 说明实型数组b,有10个元素,实型数组c,有20个元素。· char ch20; 说明字符数组ch,有20个元素。 一维数组的引用 ·

10、 数组元素的一般形式为: · 数组名下标 · 数组元素通常也称为下标变量。必须先定义数组, 才能使用下标变量。 一维数组的初始化 · 初始化赋值的一般形式为: · 类型说明符 数组名常量表达式=值,值值; · int a10= 0,1,2,3,4,5,6,7,8,9 ; · 相当于a0=0;a1=1.a9=9; 部分元素赋初值· 当 中值的个数少于元素个数时,只给前面部分元素赋值。 · int a10=0,1,2,3,4; · 表示只给a0a45个元素赋值,而后5个元素自动赋0值。 · 只能给元

11、素逐个赋值,不能给数组整体赋值。 · 例如给十个元素全部赋1值,只能写为:· int a10=1,1,1,1,1,1,1,1,1,1;· 而不能写为:· int a10=1;或int a10=1; 二维数组的定义 l 二维数组定义的一般形式是: l 类型说明符 数组名常量表达式1常量表达式2 例如· int a34; · 说明了一个三行四列的数组,数组名为a,其下标变量的类型为整型。该数组的下标变量共有3×4个 二维数组元素的引用 · 数组名下标下标 · 下标变量和数组说明在形式中有些相似,但这两者具有完

12、全不同的含义。数组说明的方括号中给出的是某一维的长度,即可取下标的最大值;而数组元素中的下标是该元素在数组中的位置标识。前者只能是常量,后者可以是常量,变量或表达式。 二维数组的初始化 · 二维数组初始化也是在类型说明时给各下标变量赋以初值。· 二维数组可按行分段赋值· 也可按行连续赋值。 字符数组 · 字符串常量是用一对双引号括起来的字符序列。 · C语言的字符串常量在内存中存储时,自动在其尾部追加一个0字符,表示字符的结束。 · 在c语言中没有字符串变量,所有字符串变量都放在字符数组中。 字符数组的输入输出 · scan

13、f()和printf()函数 · puts()和gets()函数 scanf()和printf()puts()和gets()函数 · puts()函数用来向标准输出设备(屏幕)写字符串并换行, 其调用格式为: · puts(s); · 其中s为字符串变量(字符串数组名或字符串指针)。 · puts()函数的作用与语printf("%sn", s)相同。 gets()函数· 用来从标准输入设备(键盘)读取字符串直到回车结束, 但回车符 · 不属于这个字符串。其调用格式为: · gets(s); &

14、#183; 其中s为字符串变量(字符串数组名或字符串指针)。 · gets(s)函数与scanf("%s", s)相似 字符串处理函数 · 字符串连接函数strcat · 字符串拷贝函数strcpy · 字符串比较函数strcmp · 测字符串长度函数strlen 字符串连接函数strcat · 格式: strcat (字符数组名1,字符数组名2) · 功能:把字符数组2中的字符串连接到字符数组1 中字符串的后面,并删去字符串1后的串标志“0”。本函数返回值是字符数组1的首地址。 字符串拷贝函数strcp

15、y · 格式:strcpy (字符数组名1,字符数组名2) 字符串比较函数strcmp · 格式: strcmp(字符数组名1,字符数组名2) · 功能:按照ASCII码顺序比较两个数组中的字符串,并由函数返回值返回比较结果。 · 字符串1=字符串2,返回值=0; · 字符串2>字符串2,返回值>0; · 字符串1<字符串2,返回值<0。 测字符串长度函数strlen · 格式: strlen(字符数组名) · 功能:测字符串的实际长度(不含字符串结束标志0) 并作为函数返回值。 小结

16、83; 数组是程序设计中最常用的数据结构。数组可分为数值数组(整数组,实数组),字符数组以及后面将要介绍的指针数组,结构数组等。· 数组可以是一维的,二维的或多维的。· 数组类型说明由类型说明符、数组名、数组长度(数组元素个数)三部分组成。数组元素又称为下标变量。 数组的类型是指下标变量取值的类型。· 对数组的赋值可以用数组初始化赋值,输入函数动态赋值和赋值语句赋值三种方法实现。 对数值数组不能用赋值语句整体赋值、输入或输出,而必须用循环语句逐个对数组元素进行操作。 函数· 函数的定义与调用· 函数的嵌套调用· 数组作为函数参数

17、83; 局部变量与全局变量· 变量的动态存储与静态存储 指针指针与指针变量(1)指针即地址 一个变量的地址称为该变量的指针。通过变量的指针能够找到该变量。(2)指针变量专门用于存储其它变量地址的变量指针变量num_pointer的值就是变量num的地址。指针与指针变量的区别,就是变量值与变量的区别。(3)为表示指针变量和它指向的变量之间的关系,用指针运算符“*”表示。 例如,指针变量num_pointer与它所指向的变量num的关系,表示为:*num_pointer,即*num_pointer等价于变量num。因此,下面两个语句的作用相同:num=3; /*将3直接赋给变量num*/

18、num_pointer=&num; /*使num_pointer指向num */*num_pointer=3; /*将3赋给指针变量num_pointer所指向的变量*/· 指针变量初始化的方法 · int a; int *p=&a; · 赋值语句的方法 int a; · int a; int *p; p=&a; 指针和指针变量的概念指针变量的定义与应用 数组的指针和指向数组的指针变量字符串的指针和指向字符串的指针变量结构体与枚举类型结构体的定义 定义一个结构的一般形式为:struct 结构名 成员表列 ; 其中struct是关键

19、字成员表列由若干个成员组成,每个成员都是该结构的一个组成部分。对每个成员也必须作类型说明,其形式为: 类型说明符 成员名; · 我们为学生信息定义一个结构体,包含学号、姓名、性别、五门学科的成绩 struct student int num; char name20; char sex; float score5; struct student int num; char name20; struct date birthday; char sex; float score5; ; 结构体成员可以是整型、实型、字符型、数组、指针等基本类型以外,还可以是已定义过的别的结构体类型。str

20、uct student int num; char name20; char sex; float score5; stu1,stu2; 结构体变量的定义 · struct student stu1; · 也可以同时声明多个变量struct student stu1,stu2; 在定义结构类型的同时说明结构变量。 结构变量成员的引用和初始化 表示结构变量成员的一般形式是: 结构变量名.成员名 例如:stu1.num 即第一个人的学号stu2.sex 即第二个人的性别 进行任何操作 有结构体变量stu1和stu2stu1.num=1469;gets();su

21、m += stu1.score0;printf(“%c”,stu1.sex); 进行整体赋值 如:stu1stu2;结构体变量的初始化 初始化就是在定义变量的同时给变量提供初值。和其他类型变量一样,对结构变量可以在定义时进行初始化赋值。结构体变量作函数参数 · 在ANSI C标准中允许用结构变量作函数参数进行整体传送。· 但是这种传送要将全部成员逐个传送,特别是成员为数组时将会使传送的时间和空间开销很大,严重地降低了程序的效率。· 因此最好的办法就是使用传递地址,即用结构体数组变量作函数参数进行传送。· 这时由实参传向形参的只是地址,从而减少了时间和空间

22、的开销。 枚举类型 · 枚举类型 的作用· 枚举类型的定义和枚举变量· enum 枚举名 枚举值表 ; enum weekday sun,mou,tue,wed,thu,fri,sat ;enum weekday a,b,c; 枚举类型变量的赋值和使用 · 枚举值是常量,不是变量 · 枚举元素本身由系统定义了一个表示序号的数值 #include <stdio.h>main() enum weekday sun,mon,tue,wed,thu,fri,sat a,b,c; a=sun; b=mon; c=tue; printf(&qu

23、ot;%d,%d,%d",a,b,c); 类型定义符typedef · 类型定义符typedef 的作用· typedef定义的一般形式为:· typedef 原类型名 新类型名 示例typedef int INTEGER INTEGER a,b; 它等效于: int a,b; 小节n 结构类型与结构变量的定义n 结构变量的引用与初始化n 结构数组n 枚举型n 类型定义符typedef 类与对象面向过程的语言与面相对象的语言· 面向过程的语言与面相对象的语言的区别就在于,面向过程的语言不允许程序员自己定义数据类型,而只能使用程序中内置的数据类型

24、,而为了模拟真实世界,为了更好的解决问题,往往我们需要创建解决问题所必需的数据类型类的概念· 类描述了一组有相同特性(属性)和相同行为(方法)的对象 · 类是一种引用类型,它封装数据和行为,并可以包含嵌套类型,其中数据包括常数和字段,行为包括方法、属性、索引器、事件、运算符、实例构造函数、静态构造函数和析构函数 类的特点· 封装· 继承· 多态对象· 对象是可视为一个单元的代码和数据的组合 · 对象可以是一段应用程序,如控件或窗体。整个应用程序也可以是一个对象 · 中的每个对象都由一个类来定义 · 类描述

25、对象的字段、属性、方法和事件。对象是类的实例 类和对象之间关系的两个示例 · 在 中,工具箱上的控件表示类。当将控件从工具箱拖放到窗体上时,实际上是在创建一个对象,即类的一个实例 · 在设计时使用的窗体是一个类。在运行时, 创建窗体类的一个实例 类和对象· “类”是一些内容的抽象表示形式· “对象”是类所表示的内容的可用示例· 共享类成员是此规则的一个例外,这种成员可在类的实例和声明为共享类类型的对象变量中使用 字段· 类由字段、属性、方法和事件组成· 字段和属性表示对象包含的信息· 字段类似于变量,因为可以直接读

26、取或设置它们· 例如,如果有一个名为 Car 的对象,则可以在名为 Color 的字段中存储其颜色 属性· 属性的检索和设置方法与字段类似,但是属性是使用 Property Get 和 Property Set 过程实现的,这些过程对如何设置或返回值提供更多的控制· 在存储值和使用此值的过程之间的间接层帮助隔离数据,并使您得以在分配或检索值之前验证这些值 方法· 方法表示对象可执行的操作· 例如,Car 对象可以有 StartEngine、Drive 和 Stop 方法。通过向类中添加过程(Sub 例程或函数)来定义方法 事件· 事件

27、是对象从其他对象或应用程序接收的通知,或者是对象传输到其他对象或应用程序的通知· 事件使对象得以在每当特定情况发生时执行操作· Windows 是事件驱动的操作系统,所以事件可来自其他对象、应用程序或用户输入(如鼠标单击或按键) 封装· “封装”意味着将一组相关属性、方法和其他成员视为一个单元或对象· 对象可以控制更改属性和执行方法的方式 · “封装”是包含和控制访问一组关联项的能力 · 封装还使您可以控制如何使用数据和过程 继承· 继承”描述基于现有类创建新类的能力· 新类继承基类的所有属性、方法和事件,而且可用

28、其他属性和方法自定义该新类 · 类使您可以定义封装一组相关项的数据类型 · 作为新类的基础的类称为“基类”· 从基类派生的类称为“派生类”。派生类继承基类中定义的所有字段、属性、方法和事件 多态性· “多态性”意味着可以有多个可互换使用的类,即使每个类以不同方式实现相同属性或方法· 多态性是面向对象编程的精华,因为它允许使用同名的项,而不管此时在使用什么类型的对象 重载· 重载的成员用于提供属性或方法的不同版本,这些版本具有相同名称但是接受不同数量的参数或者接受不同数据类型的参数 · 重载、重写和隐藏是很容易混淆的类似概念。

29、虽然所有这三种技术都使您得以创建同名的成员,但它们之间有一些重要的差异 重写· 重写的属性和方法用于替换在派生类中不适合的继承的属性或方法· 重写的成员必须接受同一数据类型和参数数量。派生类继承重写的成员 隐藏· 隐藏的成员用于局部替换具有更广范围的成员· 任何类型都可隐藏任何其他类型 面向对象发展历史· 诸如“对象”和“对象的属性”这样的概念,可以一直追溯到1950年代初。它们首先出现于关于人工智能的早期著作中 · OO的实际发展却是始于1966年。 当时Kisten Nygaard和Ole-Johan Dahl开发了具有更高级抽象

30、机制的Simula语言 · 1972年PARC发布了Smalltalk的第一个版本 · 大约在此时,“面向对象”这一术语正式确定 · Smalltalk被认为是第一个真正面向对象的语言。 Smalltalk 的目标是为了使软件设计能够以尽可能自动化的单元来进行 · Smalltalk语言还影响了年代早期和中期的面向对象的语言,如:Object-C (1986) , C+(1986), Self(1987),Eiffl (1987),Flavors(1986) · 1980 Grady Booch首先提出面向对象设计(OOD)的概念。然后其他人紧

31、随其后,面向对象分析的技术开始公开发表 · 1990年代以来,面向对象的分析、测试、度量和管理等研究都得到长足发展 类类定义· 类定义包含两部分:类头(class head), 由关键字class 及其后面的类名构成· 类体(classbody) 由一对花括号包围起来,类定义后面必须接一个分号或一列声明 · 在类体中,对类的数据成员和成员函数进行声明,并指定这些类成员的访问级别。类体定义了类成员表(class member list)。· 每个类定义引入一个不同的类(class )类型。即使两个类类型具有完全相同的成员表,它们仍是不同的类型 类

32、定义示例· class First int memi; double memd; ;类引用 · 在引入类型之后,我们可以以两种方式引用这种类类型:· 指定关键字class ,后面紧跟类名。在前面例子中,obj1 的声明以这种方式引用类First· 只指定类名。在前面例子中,obj2 的声明以这种方式引用Second 类引用示例· class First obj1;· class Second int memi; double memd; obj2 ;成员数据· 类数据成员的声明方式同变量声明相同 · class S

33、creen string _screen; short _height; / 行数 short _width; / 列数 ; · 与变量声明一样,我们没有必要分别声明两个short 型的成员,下列定义与上面的Screen定义是等价的 · class Screen string _screen; short _height,short _width; ; · 类数据成员可以是任意类型 · class StackScreen int topStack; void (*handler)(); / 函数的指针 vector<Screen> stack

34、; / 类的 vector ; · 除了静态static 数据成员外,数据成员不能在类体中被显式地初始化 · class First int memi = 0; / 错误 double memd = 0.0; / 错误 ;成员函数· 类的成员函数被声明在类体中。成员函数的声明看起来像是名字空间域中所出现的函数声明 · class Screen public: void home(); void move( int, int ); · 成员函数的定义也可以被放在类体内 · class Screen public: void home()

35、 _cursor = 0; char get() return _screen_cursor; ; 成员访问· 信息隐藏(Information hiding) 是为了防止程序的函数直接访问类类型的内部表示而提供的一种形式化机制 · 类成员的访问限制是通过类体内被标记为public、 private 以及protected的部分来指定的 私有成员(private member) 只能被成员函数和类的友元访问,实行信息隐藏的类把其数据成员声明为private· 被保护成员(protected member)对派生类derived class 就像public 成员一

36、样,对其他程序则表现得像privateclass Pointpublic int x, y;public Point() x = 0; y = 0;public Point(int x, int y) this.x = x; this.y = y; ; · 公有成员(public member)在程序的任何地方都可以被访问。实行信息隐藏的类将其public 成员限制在成员函数上,这种函数定义了可以被一般程序用来操纵该类类型对象的操作构造函数· 构造函数是允许控制初始化的特殊方法· 它们在程序开始之后或在创建类型的实例时运行· 与其他成员不同,构造函数不是

37、继承的,而且不向类型的声明空间引入名称· 构造函数只能由对象创建表达式调用· 它们永远不能被直接调用 析构函数· 析构函数用于销毁类的实例· 析构函数会自动被调用 class FirstFirst() cout<<"First's destructor is called"· 它们在程序结束之前或在销毁类型的实例时运行静态如何才能在类范围内共享数据· 如果我们想要在一个范围内共享某一个数据,那么我们通常会设立全局数据· 面向对象的程序是由对象构成的,需要使用静态类型static的类成员

38、 · 声明为static的类成员或者成员函数便能在类的范围内共同享· 这样的成员变量称做静态成员变量· 这样的成员函数称做静态成员函数 静态成员特点· 同一个类的所有对象共享数据项· 只会为整个类创建一个静态数据项#include <iostream.h> class Internet public: Internet(char *name,char *address) strcpy(Internet:name,name); strcpy(Internet:address,address); count+; · 只在类的内

39、部可见· 生命周期贯穿整个程序静态成员声明· 静态变量声明: static data_type variable;· 静态函数声明: static data_type function();静态成员static void Internet:Sc()/静态成员函数 cout<<count<<endl; Internet& Rq(); public: char name20; char address20; static int count; /这里如果写成static int count=0;就是错误的 ; · 应该在 ma

40、in( ) 程序开始之前创建并初始化· class A private: static int i; int j ; int A:i;静态数据成员· 是类的全局数据· 不是对象的一部分,没有 this 指针静态成员函数· 不是对象的一部分,没有 this 指针void fn(Internet &s) cout<<s.Rq().count; void main() cout<<Internet:count<<endl;/静态成员值的输出 vist(); Internet:Sc();/静态成员函数的调用 Inter

41、net b("软件开发实验室",""); Internet:Sc(); fn(b); cin.get(); · 只能操纵类的静态数据成员Internet& Internet:Rq()/返回引用的成员函数 return *this; int Internet:count = 0;/静态成员的初始化 void vist() Internet a1("软件开发实验室",""); Internet a2("软件开发实验室",""); 静态成员的引用· 静态

42、成员的使用应该是类名称加域区分符加成员名称的,在上面的代码中就是Internet:count· 我们可以使用对象名加点操作符号加成员名称的方式使用,但是不推荐的,静态态类成员的特性就是属于类而不专属于某一个对象 静态成员函数与普通成员函数的差别 · 静态成员函数与普通成员函数的差别就在于缺少this指针,没有这个this指针自然也就无从知道name是哪一个对象的成员了 静态成员的使用范围· 用来保存对象的个数。 · 作为一个标记,标记一些动作是否发生,比如:文件的打开状态,打印机的使用状态等等 · 存储链表的第一个或者最后一个成员的内存地址 本

43、章小结· 静态成员变量· 静态成员函数· 静态成员的引用· 静态成员函数与普通成员函数的差别· 静态成员的使用范围友元友元· 通常对于普通函数来说,要访问类的保护成员是不可能的· 如果想这么做那么必须把类的成员都生命成为public(共用的),然而这做带来的问题遍是任何外部函数都可以毫无约束的访问它操作它· c+利用friend修饰符,可以让一些你设定的函数能够对这些保护数据进行操作,避免把类成员全部设置成public,最大限度的保护数据成员的安全友元函数· 非成员函数不能访问私有成员· 友员函

44、数允许访问类的私有部分而不是成员· 在类里声明一个普通函数,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员 void f(A a)a.i=5;cout<<a.i<<endl;main()A a;f(a);#include "iostream.h"class Aprivate:int i;/public:friend void f(A a);· 一个类的成员函数也可以是另一个类的友元函数main(void)A a;B b;b.f(a);class Aprivate:int i;/public:fri

45、end void B:f(A a); /*;void B:f(A a) /*a.i=11;cout<<a.i<<endl;#include "iostream.h"class A;class Bpublic:void f(A a); /*;友元函数特点· 拥有访问类的私有部分的权限· 没有 this 指针· 说明可以置于类的私有或公有部分友元类 · 整个类也可以是另一个类的友元,该友元也可以称做为友元类· 友类的每个成员函数都可以访问另一个类的所有成员 main()A a;B b;b.f(a);b.g

46、(a);class Bpublic:void f(A a) /*a.i=11;cout<<a.i<<endl;void g(A a) /*a.i=22;cout<<a.i<<endl;#include "iostream.h"class B;class Aprivate:int i;/public:friend class B; /*;缺点· 违背了面向对象编程的原则· 没有源代码是无法完成的优点· 在接口设计的选择方面提供了自由度· 成员函数和友元函数具有同等的特权运算符重载语法

47、83; 定义重载运算符就象定义一个函数· 函数名使operator· 函数参数表中参数个数由运算符性质和所定义的函数性质决定(成员函数还是非成员函数)· 示例: integer& operator+=(const integer& rv) .参数和返回值· 参数和返回值的选择应该遵循合乎逻辑的模式:· 对于任何函数参数,如果仅需要从参数中读而不改变它,缺省地应当按const引用来传递它。 · 应该选择的返回值取决于运算符所期望的类型。 · 所有赋值运算符改变左值· 对于逻辑运算符,至少得到一个int

48、返回值,最好是bool返回值· 对自增、自减的运算符重载需要慎重,注意其返回效率与众不同的运算符· 运算符“ ”· 运算符“,”· 运算符new· 运算符delete不可重载的运算符· 运算符主要有:· “.”运算符· “ * ”运算符· 求幂运算符· 不允许用户定义的运算符· 不可改变运算符优先级规则本章小结ü 运算符重载存在的原因在于它可以使编程容易。ü 当它以正确的形式出现时,编译器调用这个函数。但若运算符重载对于类的设计者或类的使用者不能提供特别显著的益处,

49、则最好不要使用,因为增加运算符重载会使问题混淆。继承继承的语法· 继承的申明:· 派生类名:基类名,基类名· 派生类自动获取了基类中的数据成员和成员函数构造函数的初始化表达式· 成员对象初始化· 在初始化表达式表中的内置类型· 构造函数和析够函数的次序· 名字隐藏· 非自动继承的函数成员对象初始化· 如果在初始化表达式表中有多于一个构造函数调用,应当用逗号隔开:· foo2:foo2(int I) : bar(i), memb(i+1) / .· 表明:类foo2 构造函数是从bar

50、继承来的,包含称为memb 的成员对象。· 注意:当在这个构造函数的初始化表达式表中能看到基类的类型时,只能看到成员对象的标识符在初始化表达式表中的内置类型· 在构造函数的初始化表达式表中允许显式调用成员对象的构造函数 · 在进入新类的构造函数体之前调用所有的构造函数· 即:进入构造函数之前,调用对所有的成员对象和基类对象的构造函数 · 自动析构函数调用构造函数和析够函数的次序· 构造在类层次的最根处开始,而在每一层,首先调用基类构造函数,然后调用成员对象构造函数· 调用析构函数则严格按照构造函数相反的次序 · 对

51、于成员对象,构造函数调用的次序完全不受在构造函数的初始化表达式表中次序的影响。该次序是由成员对象在类中声明的次序所决定的 名字隐藏· 如果在基类中有一个函数名被重载几次,在派生类中重定义这个函数名会掩盖所有基类版本,这也就是说,它们在派生类中变得不再可用 非自动继承的函数· 不是所有的函数都能自动地从基类继承到派生类中的 · 构造函数和析构函数不能被继承 · operator= 也不能被继承组合与继承的选择· 无论组合还是继承都能把子对象放在新类型中,两者都使用构造函数的初始化表达式表去构造这些子对象。· 主要涉及:· 子类

52、型设置· 专门化· 私有继承专门化与私有继承· 继承也就是取一个已存在的类,并制作它的一个专门的版本。通常,这意味着取一个一般目的的类并为了特殊的需要对它专门化· 通过在基类表中去掉public 或者通过显式地声明p r i v a t e,可以私有地继承基类 · 对私有继承成员公有化保护· 保护的含义:“就这个类的用户而言,它是private的,但它可被从这个类继承来的任何类使用。”· 对被保护的类继承时,基类缺省为private,这意味着所有public成员函数对于新类的用户是private的。通常都会让继承public

53、,从而使得基类的接口也是派生类的接口。然而在继承期间,也可以使用protected关键字。· 被保护的派生意味着对其他类来“照此实现”,但对派生类和友元是“is-a”。它是不常用的,它的存在只是为了语言的完整性 多重继承· 多重继承是一个有争议的话题 · 不管我们如何认为必须用多重继承,我们总能通过单重继承来完成· 起初多重继承似乎很简单,在继承期间,只需在基类表中增加多个类,用逗号隔开。然而,多重继承有很多含糊的可能性 渐增式开发· 继承的优点之一是它支持渐增式开发,它允许我们在已存在的代码中引进新代码,而不会给原代码带来错误,即使产生了错误

54、,这个错误也只与新代码有关 · 继承首先表示一种关系,其意为:“新类是老类的一个类型。” 向上映射· 为什么“向上映射”· 继承的最重要的方面不是它为新类提供了成员函数,而在于它是基类与新类之间的关系描述:“新类是已存在类的一个类型” · 在顶部是根,向下长,继承是从派生类到基类的映射,在继承图中是上升的,所以一般称为向上映射 · 组合与继承确定应当用组合还是用继承,最清楚的方法之一是询问是否需要新类向上映射 · 指针和引用的向上映射· 向上映射还能出现在对指针或引用简单赋值期间(示例)· 危机· 任何向

55、上映射都会损失对象的类型信息 本章小结· 继承和组合都允许由已存在的类型创建新类型,两者都是在新类型中嵌入已存在的类型的子对象。然而,当想重用原类型作为新类型的内部实现的话,最好用组合,如果不仅想重用这个内部实现而且还想重用原来接口的话那就用继承。如果派生类有基类的接口,它就能向上映射到这个基类,这一点对多态性很重要。· 虽然通过组合和继承进行代码重用对于快速项目开发有帮助,但通常我们会希望在允许其他程序员依据它开发程序之前重新设计类层次。· 类层次必须有这样的特性:它的每个类有专门的用途,不能太大(包含太多的功能不利于重用),也不能太小(太小如不对它本身增加功能

56、就不能使用)。而且这些类应当容易重用。多态性多态和虚函数· 多态性的定义· 多态性(在C+中用虚函数实现)是面向对象程序设计语言继数据抽象和继承之后的第三个基本特征。它提供了与具体实现相隔离的另一类接口· 虚函数反映了一个类型与另一个类似类型之间的区别,只要这两个类型都是从同一个基类派生的。这种区别是通过其在基类中调用的函数的表现不同来反映的 问题· 函数调用捆绑· 函数调用与函数体相联系(早捆绑)· 晚捆绑,这意味着捆绑在运行时发生,又称为动态捆绑或运行时捆绑 · 当一个语言实现晚捆绑时,必须有一种机制在运行时确定对象的类

57、型和合适的调用函数。这就是,编译器还不知道实际的对象类型,但它插入能找到和调用正确函数体的代码 虚函数· 申明方式· 对于特定的函数,为了引起晚捆绑,C+要求在基类中声明这个函数时使用virtual关键字。 · 创建一个virtual成员函数,可以简单地在这个函数声明的前面加上关键字virtual · 示例,并观察结果C+晚捆绑的实现· 所有的工作都由编译器在幕后完成 · 用创建虚函数告诉编译器,编译器安装必要的晚捆绑机制 · 编译器对每个包含虚函数的类创建一个表(称为VTABLE)。在VTABLE中,编译器放置特定类的虚函数地址· 在每个带有虚函数的类中,编译器秘密地置一指针,称为vpointer(缩写为VPTR),指向这个对象的VTABLE。通过基类指针做虚函数调用时(也就是做多态调用时),编译器静态地插入取得这个VPTR,并在VTABLE表中查找函数地址的代码,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论