湖大 C++ 程序设计829 大纲知识点
2021-01-29 15:37:18 1 举报
AI智能生成
湖南大学考研829程序设计大纲知识点
作者其他创作
大纲/内容
绪论
计算机程序设计语言的发展
1. 由计算机硬件系统可以识别的二进制指令组成的语言称为机器语言
2. 汇编语言,它将机器指令映射为一些可以被人读懂的助记符。由汇编程程序充当翻译。
3. 高级语言,屏蔽了机器的细节,提高了语言的抽象层次,程序中可以采用具有一定含义的数据命名和容易理解的执行语句
4. 面向对象的编程语言设计的出发点就是为了能更直接地描述客观世界中存在的事物(即对象)以及它们之间的关系
5. 面向对象的编程语言将客观事物看作具有属性和行为(或称服务)的对象,通过抽象找出同一类对象的共同属性(静态特征)和行为(动态特征),形成类
什么是面向过程的方法?
1. 自顶而下、逐步求精;
2. 其程序结构是按功能划分为若干个基础模块,这些模块形成一个树状结构 。程序模块是由函数构成的
3. 各模块之间的关系尽可能简单,在功能上相对独立;
4. 每一模块内部均是由顺序、选择和循环3种基本结构组成;
5. 其模块化实现的具体方式是使用子程序;
什么是面向对象的方法呢?
1. 它将数据及对数据的操作方法封装在一起,作为一个相互依存、不可分离的整体----对象。
2. 对同类型对象抽象出其共性,形成类。 程序模块是由类构成的。
3. 类中的大多数数据,只能用本类的方法进行处理。
4. 类通过一个简单的外部接口与外界发生关系,对象与对象之间通过消息进行通信。
面向对象的基本概念
1. 对象:是系统中用来描述客观事物(有形或无形)的一个实体,它是用来构成系统的一个基本单位。对象由一组属性和一组行为构成
2. 类:是具有相同属性和服务的一组对象的抽象。
3. 封装:是面向对象方法的一个重要原则,就是把对象的属性和行为结合成一个独立的系统单位,并尽可能隐藏对象的内部细节。
4. 继承:特殊类对象拥有其一般类的全部属性与服务,称做特殊类对一般类的继承。
增加了程序复用,提高了软件开发效率,同时使开发者专注特殊类独有的那些特性
增加了程序复用,提高了软件开发效率,同时使开发者专注特殊类独有的那些特性
5. 多态性:是指在一般类中定义的属性和行为,被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
信息的表示与存储
信息的单位通常采用:
位(bit):度量数据的最小单位,表示1位二进制信息
字节(Byte):一个字节由8位二进制数字组成(1Byte=8bit),是信息存储中最常用的基本单位。
字(Word):字是位的组合,并作为一个独立的信息单位处理(了解)
几种进位记数制之前的转换
R进制转换为十进制:基数为R的数字,只要将各位数字与它的权相乘,其积相加,和数就是十进制数
十进制转换为R进制
将此数分成整数和小数两部分分别转换,然后再拼接起来即可
将此数分成整数和小数两部分分别转换,然后再拼接起来即可
十进制整数转换成R进制的整数:除R取余法,除下去,直到商为0时为止(从上到下,是低位->高位)
十进制小数转换成R进制小数:乘R取整,乘下去,直到小数部分为0或达到所要求的的精度为止
示例:68.3125(十进制) = 1000100.0101(二进制)
二、八、十六进制的相互转换
每位八进制数相当于3位二进制数,每位十六进制数相当于4位二进制数
在转换时,位组划分是以小数点为中心向左右两边延伸,中间的0不能省略,两头不够时可以补0
二进制的编码表示
一个数在机内的表达形式称为“机器数”,而它代表的数值称为此机器数的“真值”
用"0"表示正号,"1"表示负号,符号位放在数的最高位
原码:
将符号位数字化为0或1,数的绝对值与符号一起编码,即所谓"符号-绝对值表示"的编码,称为原码
该表示法,零的表示不唯一
反码
正数的反码与原码表示相同
负数反码的符号位与原码相同,其余各位取反
该表示法,零的表示不唯一
补码
正数的原码、反码、补码表示相同
对于负数,其补码由该数的反码的最末位加1求得
补码运算规则
符号位可作为数值参加运算
负数采用补码表示后,可以使加减法统一为加法运算
补码运算的结果仍为补码
计算机内数字,以补码形式存储
人们研究了符号数的多种二进制编码方法,其实质是对负数表示的不同编码
数据类型
基本数据类型
bool
false, true
char
[signed]char
-128~127
unsigned char
0~255
int
[signed]short
-32 768~32 767
unsigned short
0~65535
[signed]int
-2 147 483 648~2 147 483 647
unsigned int
0~4 294 967 295
[signed]long
-2 147 483 648 ~2 147 483 647
unsigned long
0~4 294 967 295
float
-3.4E-38~3.4E+38
注意 指数形式 表示法
double
double
1.7E-308~1.7E+308
long double
1.7E-308~1.7E+308
字符串
可将字符串常量赋给字符串指针,由于常量值是不能改变的,应将字符串常量赋给指向常量的指针
示例:const char * STRING1 = "This is a string.";
示例:const char * STRING1 = "This is a string.";
如果创建一个char数组,每个元素存放字符串的一个字符,在末尾放置一个'\0',便构成了C++字符串
示例:下面3中写法等价
char str[8]={'p','r','o','g','r','a','m','\0'};
char str[8]="program";//注意,用于存放字符串的数组,其元素个数应该不小于字符串长度+1(存放'\0',标识字符串结束)
char str[]="program";
char str[8]={'p','r','o','g','r','a','m','\0'};
char str[8]="program";//注意,用于存放字符串的数组,其元素个数应该不小于字符串长度+1(存放'\0',标识字符串结束)
char str[]="program";
string
string类的操作符:+ = += == != < <= > >= []
需引用头文件string,示例:#include <string>
常用成员函数
string & insert(unsigned int p0, const char * s);//将s所指向的字符串插入到本串中的位置p0之前
string substr(unsigned int pos, unsigned int n) const;//取子串,取本串中位置pos开始的n个字符,构成新的string类对象作为返回值
unsigned int find(const basic_string &str) const;//查找并返回str在本串中第一次出现的位置
unsigned int length() const;//返回串的长度(字符个数)
获取字符串长度
strlen(str)是用于求字符数组的长度,其参数是char*,需#include<cstring>
str.length()和str.size()是用于求string类对象字符串长度
int len=0; for(int i=0;str[i]!='\0';i++) len++;
枚举类型(enum)
示例:enum Weekday { SUN, MON, TUE, WED, THU, FRI, SAT };//枚举元素具有默认值,它们依次为:0,1,2...
整数值不能直接赋给枚举变量,应进行强制转换,示例:(Weekday)count;
枚举型数据可以隐含转换为整型数据,示例 int count=SAT;
可与整型数据进行关系运算,示例:for(int i=0; i<=SAT; i++){}
指针
概念:专门存放内存单元地址的变量类型
指针变量的声明:int * ptr;
为什么声明时,要指出类型?
1、声明变量需要的内存空间
2、限定对变量可以进行的运算及其运算规则
int &rf;//声明一个int型的引用rf
与地址相关的运算*和&
*:指针运算符,获取指针所指向的变量的值
&:取地址运算符
指针的赋值
定义指针,其中的地址值是一个不确定的数,因此需先赋值后使用
指向整数常量的指针:const int * pl=&a;
指针常量:int * const p2=&a;
数组名实际上是一个不能被赋值的指针,即指针常量
void 类型指针,可以存储任何类型的对象地址
指针运算
算术运算:p1[n1]与*(p1+n1)的写法完全等价
关系运算:可以和整数0(NULL)比较,0专用于表示空指针,即一个不指向任何有效地址的指针
赋值运算:必须是地址常量(如数组名)或地址变量,不能是非0整数,可以赋值为0
用指针处理数组元素
int * p=a;*(p+i);*(p++);
指针型函数:返回值是指针类型的函数
主要目的是要在函数结束时将大量的数据从被调函数返回到主调函数中
指向函数的指针
程序运行中,不仅数据要占据内存空间,执行程序的代码被调入内存并占据一定空间。
函数名就表示函数代码首地址
函数指针就是专门用于存放函数代码首地址的变量
示例:void (* functionPointer)(float);
对象指针
示例:Point * pointPtr=&p1; pointPtr->getX();
this指针
指向类的非静态成员的指针
指向非静态数据成员
赋值:int Point::*p = &Point::a;
调用:a.*p 或 p1->*p
调用:a.*p 或 p1->*p
指向非静态函数成员
赋值:int (Point :: *funcPrt)() const = &Point::getX;
调用:a.*funcPrt)() 或 p1->*funcPrt)()
调用:a.*funcPrt)() 或 p1->*funcPrt)()
指向类的静态成员的指针
指向静态数据成员
赋值:int *p = &Point::a;
调用:*p
调用:*p
指向静态函数成员
赋值:int (*funcPrt)() const = &Point::getX;
调用:funcPrt)()
调用:funcPrt)()
数组
示例:int a[3] = { 1, 2, 3 };
int a[] = { 1, 2, 3 };
int a[5] = { 1, 2, 3 }; //剩余的数组元素会被赋予0值
int a[2][3]={1,0,0,0,1,0};等价于int a[][3]={1,0,0,0,1,0};int a[2][3]={{1,0,0},{0,1,0}};
char chs[]="This is a string";char * p = chs;
char chs[2][20]={"This is a string1", "This is a string2"};
string strs[] = {"This is a string1", "This is a string2"};
int a[] = { 1, 2, 3 };
int a[5] = { 1, 2, 3 }; //剩余的数组元素会被赋予0值
int a[2][3]={1,0,0,0,1,0};等价于int a[][3]={1,0,0,0,1,0};int a[2][3]={{1,0,0},{0,1,0}};
char chs[]="This is a string";char * p = chs;
char chs[2][20]={"This is a string1", "This is a string2"};
string strs[] = {"This is a string1", "This is a string2"};
数组的声明与使用
数组大小,必须是编译时可求出的常量表达式
数组的存储与初始化
数组元素在内存中是顺序、连续存储的
声明为常量的数组,必须给定初值,示例:const int a[3] = { 1, 2, 3 };
数组作为函数参数
使用数组名传递数据时,传递的是地址
把数组作为参数时,一般不指定数组第一维的大小,但之后维度必须指定
对象数组
Location a[2] = {Location(1,2)};//在执行时首先调用带形参的构造函数初始化a[0],然后调用默认构造函数初始化a[1]
指针数组 Student * p[3]
根据[]、*运算符优先级([]>*),区分指针数组与数组指针
Student * stu[] = { &stu1, &stu2, &stu3 }; //指针数组,大数据结构一般采用指针数组,避免复制数据的性能开销
int array2[3][3]={{11,12,13},{21,22,23},{31,32,33}};
arrat2[i][j]与*(array2[i]+j)等价
可以用*(array2[0])来表示array2[0][0],用*(array2[0]+1)来表示array2[0][1]
arrat2[i][j]与*(array2[i]+j)等价
可以用*(array2[0])来表示array2[0][0],用*(array2[0]+1)来表示array2[0][1]
指向数组的指针Student (*p)[3]
这是指向一个长度为3的数组的指针变量,p指针+1则指向二维数组的下一行
Student *p,既可以指向Student类型对象,也可以指向Student类型数组,指向数组时,p指针+1则指向数组的下一个元素
求数组长度
int arr[4]; int len = sizeof(arr)/sizeof(arr[0]或int)
注意:char str[]="This is a string"; sizeof(str)/sizeof(char)-1;//得到字符串长度。
若类型为char *str,应#include <cstring>,通过strlen(str)获取其正确长度
若类型为char *str,应#include <cstring>,通过strlen(str)获取其正确长度
类(class)
前向引用声明
结构体(struct)
结构体是一种特殊形态的类
唯一区别在于,默认访问控制属性为public
特殊情况下,赋初值方式
示例:Student stu1={97001, "Lin Lin", 'F', 19}; Student * p = &stu1;//指向Student类型对象的指针变量
Student * stu[] = { &stu1, &stu2, &stu3 }; //指针数组,大数据结构一般采用指针数组,避免复制数据的性能开销
Student * stu[] = { &stu1, &stu2, &stu3 }; //指针数组,大数据结构一般采用指针数组,避免复制数据的性能开销
C++引入结构体,是为了保持和C程序的兼容性
联合体(union)
联合体是一种特殊形态的类
区别
默认访问控制属性为public
不能有自定义的构造函数、析构函数和重载的赋值运算符,其对象成员及对象成员的对象成员也不能有
不能继承,不支持多态
联合体的全部数据成员共享同一组内存单元
一般只用联合体来存储一些公有的数据,而不为它定义函数成员
无名联合体
函数
基本概念:主调函数、被调函数
函数的定义就属于函数的声明。如果希望在定义一个函数前调用它,则需要在调用函数前添加该函数的函数声明
递归调用
概念:函数可以直接或间接调用自身
递归的过程有如下两个阶段:
第一:递推。将原问题不断分解为新的子问题,逐渐从未知向已知推进,最终达到已知的调解,即递归结束的条件,这是递推阶段结束
第二:回归。从已知的条件出发,按照递推的逆过程,逐一求值回归,最后达到递推的开始处,结束回归阶段,完成递归调用
函数的参数传递
函数未被调用时,函数的形参并不占有实际的内存空间,也没有实际的值。
只有在函数被调用时才为形参分配存储单元,并将实参和形参结合。
只有在函数被调用时才为形参分配存储单元,并将实参和形参结合。
值传递
指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参。注:指针也属值传递,即地址初始化到形参内存空间
引用传递
引用是一种特殊类型的变量,可以被认为是一个变量的别名,示例: void swap(int &a, int &b){}
声明一个引用时,必须同时对它进行初始化,使他指向一个已存在的对象
引用只能在初始化时指定被引用的对象,其后不能更改
用指针作为函数参数
1、达到参数双向传递的目的
2、减少函数调用时数据传递的开销
3、通过指向函数的指针传递函数代码的首地址
void splitFloat(float x, int * intPart, float * floatPart){}
传参示例:splitFloat(x, &n, &f);
传参示例:splitFloat(x, &n, &f);
带默认形参值的函数
函数在定义时,可以预先声明默认的形参值,有默认值的形参必须放参数列表的最后
相同作用域内,不允许在同一个函数的多个声明中对同一个参数的默认值重复定义,即使前后定义的值相同也不行
如果一个函数在定义之前又有原型声明,则默认形参值需在原型声明中给出
函数重载
两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同(注:不关心返回值)
系统函数
常用数学函数:sin、cos、tan、sqrt、pow、exp、fabs、log等
常用字符函数:isalnum、isalpha、isdigit、islower、toupper等
常用字符串函数:strcpy、strcmp、strcat、strlen等
郑莉:例3-2、例3-4、例3-9、例3-10
线性群体
对可直接访问的线性群体,我们可以直接访问群体中的任何一个原始,如:数组
对顺序访问的线性群体,只能按元素的排列顺序从头开始依次访问各个元素
如:链表
如:链表
结点类:包括数据和指针域,是链表的基本构件
只有一个指向后继结点的指针,称为单链表
有两个指针,一个指向前趋结点,一个指向后继结点,则构成双向链表
链表类
数据成员:表头指针、表尾指针、元素个数、当前遍历位置等
成员函数:生成新结点,插入结点、删除结点、遍历链表、访问/修改结点数据等
遍历
while(node != NULL){ ...; node = node->next; }
插入
删除
另外,还有两种特殊的线性群体
栈
栈是只能从 一端访问的线性群体,可以访问的一端称为栈顶,
栈顶添加元素称为"压入栈", 删除栈顶元素称为"弹出栈", 具有"后进先出"(LIFO)的特性
栈顶添加元素称为"压入栈", 删除栈顶元素称为"弹出栈", 具有"后进先出"(LIFO)的特性
队列
队列是只能向一端(队尾)添加元素,从另一端删除(队头)元素的线性群体。
向队尾添加元素称为"入队", 删除队头元素称为"出队", 具有"先进先出"(FIFO)的特性
向队尾添加元素称为"入队", 删除队头元素称为"出队", 具有"先进先出"(FIFO)的特性
常量
整型常量
八进制:数字部分要以数字0开头,示例:0123
十六进制:数字部分要以0x开头,示例:0x5af
八进制和十六进制形式的整型常量一般用来表示无符号整数,不应带正负号
整型常量可以用后缀字母L(或l)表示长整型,后缀字母U(或u)表示无符号型,也可同时后缀L和U(大小写无关)
示例:-123,0123,0x5af都是合法的常量形式
实型常量
一般形式,示例:12.5,-12.5
指数形式(科学记数法),示例:0.354E+2,-34.4E-3
实型常量默认为double型,如果后缀F(或f)可以使其成为float型,示例:12.3f
字符常量
熟悉常见转义序列(\n,\r,\t,\v,\b),转义符号为"\"
\nnn 八进制形式
\xnnn 十六进制形式,示例:'a'可以表示为'\x61'
字符串常量
"This is a string."
它在内存中的存放形式是:按串中字符的排列次序顺序存放,每一个字符占一个字节,并在末尾添加'\0'作为结尾标记
布尔常量
false,true
符号常量
符合常量在声明时一定要赋初值,在程序中间不能修改,示例:const float PI=3.1415926;
常用符号常量:NULL、EOF
常对象
常对象的数据成员值在对象的整个生存期间内不能被改变
常对象必须进行初始化(且只能用初始化列表来初始化),不能被更新
常对象只能调用常成员函数,而不能调用普通成员函数
区分常对象、常量指针、常引用、指针常量
语法:const 类型说明符 对象名;
用const修饰的类成员
常成员函数
语法:类型说明符 函数名(参数表) const;
只能调用常成员函数,不能调用普通成员函数
对于无须改变对象状态的成员函数,都应当使用const
const 关键字可以用于对重载函数的区分。
常数据成员
任何函数不能对该成员赋值。常数据成员只能通过构造函数初始化列表来获得初值。
示例:const int a;//常数据成员在类定义中进行声明 const int A::b=10;//静态常数据成员在类外说明和初始化
【例外】类的静态常量如果具有整数类型或枚举类型,那么可以直接在类定义中为它指定常量值,示例:static const int b=10;
常引用
如果在声明引用时用const修饰,被声明的引用就是常引用。常引用所引用的对象不能被更新。
如果用常引用做形参,便不会意外地发生对实参的更改
如果用常引用做形参,便不会意外地发生对实参的更改
语法:const 类型说明符 & 引用名;
非const的引用只能绑定到普通的对象,而不能绑定到常对象(避免误修改),但常引用可以绑定到常对象
一个常引用,无论是绑定到一个普通的对象,还是常对象,通过该引用访问该对象时,都只能把该对象当作常对象
对于在函数中无须改变其值的参数,宜采用常引用传递;使用普通引用传递时,常对象无法被传入;
变量
概念:在程序执行过程中其值可以变化的量称为变量,示例:int i=0; int i=0,j=1;
定义一个变量意味着给变量分配内存空间,变量名就是对相应内存单元的命名
变量存储类型
auto存储类型:采用堆栈方式分配内存空间,属于暂时性存储,其存储空间可以被若干变量多次覆盖使用
register存储类型:存放在通用寄存器中(频繁使用的数据)
extern存储类型:在所有函数和程序段中都可以引用
static存储类型:在内存中是以固定地址存放的,在整个程序运行期间都有效
作用域
概念:标识符在程序正文中有效的区域
分类:函数原型作用域、局部作用域(块作用域)、类作用域、命名空间作用域
命名空间作用域
语法形式:namespace 命名空间名 {}
概念:在命名空间之内声明的,不属于前面所述各个作用域的标识符,都属于命名空间作用域
使用:1、命名空间名::标识符(可嵌套,示例:OuterNs::InnerNs::SomeClass)
2、using 命名空间名::标识符
3、using 命名空间名(C++标准库所有标识符都声明在std命名空间中)
2、using 命名空间名::标识符
3、using 命名空间名(C++标准库所有标识符都声明在std命名空间中)
全局命名空间:在显式声明的命名空间之外声明的标识符都在一个全局命名空间中
匿名命名空间:即显式声明的没有名字的命名空间:示例:namespace {}
具有命名空间作用域的变量也称为全局变量
可见性
概念:标识符在程序中能够被引用到的区域
同一个作用域中,不能声明同名的标识符
在两个或多个具有包含关系的作用域中声明了同名标识符,则外层标识符在内层不可见(同名变量被隐藏)
生存期
静态生存期
概念:如果对象的生存期与程序的运行期相同,则称它具有静态生存期
在命名空间作用域中声明的对象都是具有静态生存期的,局部作用域声明具有静态生存期的对象,需用到static关键字
生存期内值共享
定义时未指定初值的基本类型静态生存期对象,会被赋予0值初始化
对于动态生存期变量,不指定初值意味着初值不确定
对于动态生存期变量,不指定初值意味着初值不确定
动态生存期
除了命名空间作用域内及static修饰的,其他的都是动态生存期
在程序运行过程中申请(new)和释放(delete)的存储单元也称为堆对象
运算符new的功能是动态分配内存,或者称为动态创建堆对象,语法:new 数据类型(初始化参数列表); //注意使用指针类型接收(数据类型 *)
如果不希望在分配内存后设定初值,可以把括号省去,示例:int * point = new int;
"new T" 和 "new T()"两种写法的效果相同,都调用默认构造函数,还会为基本数据类型和指针类型的成员用0赋初值。
用new分配的内存,必须用delete加以释放,如果被删除的是对象,该对象的析构函数将被调用,语法:delete 指针名;
如果是用new建立的数组,用delete删除时在指针名前面要加"[]",示例: delete [] 指针名;
如果不希望在分配内存后设定初值,可以把括号省去,示例:int * point = new int;
"new T" 和 "new T()"两种写法的效果相同,都调用默认构造函数,还会为基本数据类型和指针类型的成员用0赋初值。
用new分配的内存,必须用delete加以释放,如果被删除的是对象,该对象的析构函数将被调用,语法:delete 指针名;
如果是用new建立的数组,用delete删除时在指针名前面要加"[]",示例: delete [] 指针名;
输入输出
预定义的插入法和提取符
插入符:<< 示例:cout << "Hello!" << endl;
提取符:>> 示例:int a, b; cin >> a >> b;
常见的I/O流类库操纵符
需引用头文件iomanip
dec 数值数据采用十进制表示
hex 数值数据采用十六进制表示
oct 数值数据采用八进制表示
endl 插入换行符,并刷新流
setprecision(int) 设置浮点数的小数位数(包括小数点)
setw(int) 设置域宽
示例:cout << setw(5) << setprecision(3) << 3.1415 << endl
cout << "这个数的十六进制形式为:" << hex << n << endl;
hex 数值数据采用十六进制表示
oct 数值数据采用八进制表示
endl 插入换行符,并刷新流
setprecision(int) 设置浮点数的小数位数(包括小数点)
setw(int) 设置域宽
示例:cout << setw(5) << setprecision(3) << 3.1415 << endl
cout << "这个数的十六进制形式为:" << hex << n << endl;
字符串
直接使用cin的">>"操作符从键盘输入字符串时,空格会被作为输入的分隔符
如果希望读取直到行末为止,不易中间空格作为输入的分隔符,可使用头文件string中定义的getline,示例:getline(cin, s2)
可以指定分隔符,示例:getline(cin, s2, ',')
可以指定分隔符,示例:getline(cin, s2, ',')
流
在C++中,将数据从一个对象到另一个对象的流动抽象为“流”
当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象。
流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动。
程序建立一个流对象,并指定这个流对象与某个文件对象建立连接,程序操作流对象,流对象通过文件系统对所连接的文件对象产生作用。
对于程序对象而言,文件对象有的特性,流对象也有,所以程序将流对象看作是文件对象的化身。
操作系统将键盘、屏幕、打印机和通信端口作为扩充文件来处理,从C++程序员角度看,它们与磁盘文件是等同的,与这些设备的交互也是通过I/O流类来实现的
流是一种抽象,它负责在数据的生产者和数据的消费者之间建立联系,并管理数据的流动。
程序建立一个流对象,并指定这个流对象与某个文件对象建立连接,程序操作流对象,流对象通过文件系统对所连接的文件对象产生作用。
对于程序对象而言,文件对象有的特性,流对象也有,所以程序将流对象看作是文件对象的化身。
操作系统将键盘、屏幕、打印机和通信端口作为扩充文件来处理,从C++程序员角度看,它们与磁盘文件是等同的,与这些设备的交互也是通过I/O流类来实现的
一般意义下的读操作在流数据抽象中称为(从流中)提取,写操作被称为(向流中)插入
插入运算符
插入("<<")运算符用于传送字节到一个输出流对象,示例:cout << "This is a string"
提取运算符
提取(">>")运算符用于格式化文本输入,在提取数据时,以空白符为分隔
注:要输入一段包含空白符的文本,用提取运算符就很不方便,选择使用非格式化输入成员函数getline,就可以读一个包含有空格的文本块
注:要输入一段包含空白符的文本,用提取运算符就很不方便,选择使用非格式化输入成员函数getline,就可以读一个包含有空格的文本块
文件输出流
ofstream
ofstream
常用构造方式
1. 使用默认构造函数建立对象,然后调用open成员函数打开文件,示例:ofstream myFile; myFile.open("filename");
2. 在调用构造函数时,指定文件名和模式,在构造过程中打开该文件,示例:ofstream myFile("filename")
3. 使用同一个流先后打开不同的文件(在同一时刻只有一个是打开的),示例 ofstream file; file.open("file1"); file.close(); file.open("file2"); file.close();
成员函数
open:打开一个与输出流关联的文件时,可以指定一个open_mode标志,可以用按位或("|")运算符组合这些标志
示例:file.open("filename", ios_base::out|ios_base::binary);
注:路径中反斜杠"D:\"注意要转义为"D:\\",斜杠"D:/"则不需要转义
示例:file.open("filename", ios_base::out|ios_base::binary);
注:路径中反斜杠"D:\"注意要转义为"D:\\",斜杠"D:/"则不需要转义
close:文件使用完毕后必须将其关闭(ofstream析构函数会自动完成关闭,但一般建议程序员调用close手动关闭)
put:put函数把一个字符写到输出流中,示例:cout.put('A'); cout << 'A'; //两个语句默认是相同的,但第二个受该流的格式化参数影响
write:write函数把一个内存中的一块内容写到一个文件输出流中,长度参数指出写的字节数,示例:file.write(reinterpret_cast<char *>(&dt), sizeof(dt));
seekp和tellp函数:一个文件输出流保存一个内部指针指出下一次写数据的位置。
seekp成员函数设置这个指针,因此可以以随机方式向磁盘文件输出。
tellp成员函数返回该文件位置指针。
seekp成员函数设置这个指针,因此可以以随机方式向磁盘文件输出。
tellp成员函数返回该文件位置指针。
错误处理函数
写入操作
put、write、"<<"(插入运算符)
文件输入流
ifstream
ifstream
常用构造方式
1. 使用默认构造函数建立对象,然后调用open成员函数打开文件,示例:ifstream myFile; myFile.open("filename");
2. 在调用构造函数时,指定文件名和模式,在构造过程中打开该文件,示例:ifstream myFile("filename")
3. 使用同一个流先后打开不同的文件(在同一时刻只有一个是打开的),示例 ifstream file; file.open("file1"); file.close(); file.open("file2"); file.close();
成员函数
open:打开一个与输出流关联的文件时,可以指定一个open_mode标志,可以用按位或("|")运算符组合这些标志
示例:file.open("filename", ios_base::in|ios_base::binary);
示例:file.open("filename", ios_base::in|ios_base::binary);
close:文件使用完毕后必须将其关闭(ofstream析构函数会自动完成关闭,但一般建议程序员调用close手动关闭)
get:get函数在读入数据时包括空白字符
getline:getline函数允许从输入流中读取多个字符,且允许指定输入终止字符(默认值是换行符)。
建议使用string头文件内,非成员函数getline,示例:getline(cin, line, 't')
建议使用string头文件内,非成员函数getline,示例:getline(cin, line, 't')
read:read成员函数从一个文件读字节到一个指定的存储区域,由长度参数确定要读的字节数,
示例:file.read(reinterpret_cast<char *>(&employee), sizeof(employee));
示例:file.read(reinterpret_cast<char *>(&employee), sizeof(employee));
seekg和tellg函数:一个文件输入流中,保留着一个指向文件中下一个将读数据的位置的内部指针,
seekg成员函数设置这个指针,示例:file.seekg(3*sizeof(int));
tellg成员函数返回该文件位置指针,这个值是streampos类型,示例:streampos here = file.tellg(); cout << "Position " << here << endl
seekg成员函数设置这个指针,示例:file.seekg(3*sizeof(int));
tellg成员函数返回该文件位置指针,这个值是streampos类型,示例:streampos here = file.tellg(); cout << "Position " << here << endl
读取操作
get、getline、read、">>"(提取运算符)
文件状态检查:if(file){...}//判断打开的文件是否有错误
运算符与表达式
优先级
初等运算符(() [] -> .)
> 单目运算符
> 算术运算符(先乘除,后加减)
> 关系运算符(< <= > >=)
> 逻辑运算符(&& ||)(不包括!)
> 条件运算符(? :)
> 赋值运算符(= += -= *= /= %= >>= <<= &= ^= |=)
> 逗号运算符;
单目运算符 > 双目运算符;
> 单目运算符
> 算术运算符(先乘除,后加减)
> 关系运算符(< <= > >=)
> 逻辑运算符(&& ||)(不包括!)
> 条件运算符(? :)
> 赋值运算符(= += -= *= /= %= >>= <<= &= ^= |=)
> 逗号运算符;
单目运算符 > 双目运算符;
详细说明请参考谭浩强版《C语言程序设计》附录D
结合性
仅 单目运算符、条件运算符、赋值运算符 为 自右到左,其余都为 自左到右
&& 和 || 运算符具有“短路”特性
sizeof运算符:用于计算某种类型的对象在内存中所占的字节数
位运算
按位与(&):使用按位与操作可以将操作数中的若干位置0(其他位不变);或者取操作数中的若干指定位
按位或(|):可以将操作数中的若干位置1
按位异或(^):异则为1,同则为0。可以将操作数中的若干位翻转
按位取反(~)、移位(<< >>,移位运算符左边的表达式值本身不会被改变)
按位与(&):使用按位与操作可以将操作数中的若干位置0(其他位不变);或者取操作数中的若干指定位
数据类型的转换
隐式转换
转换的基本原则是将低类型数据转换为高类型数据(应用与混合运算时)
char->short->int->long->float->double(这种转换是安全的,因为过程中数据的精度没有损失)
char->short->int->long->float->double(这种转换是安全的,因为过程中数据的精度没有损失)
赋值运算,不适用上述原则,一律将右值类型转换为左值类型
显式转换
类型说明符(表达式) //C++风格
(类型说明符)表达式 //C语言风格
郑莉:课后习题2-24、2-25
语句&控制结构
在表达式末尾添加";"便构成了一个表达式语句,将多个语句用一对大括号包围,便构成一个复合语句
选择结构
if else
switch(表达式){
case 常量表达式: 语句 ...
default: 语句...
}
case 常量表达式: 语句 ...
default: 语句...
}
每个case分支可以有多条语句,但不必用{}
每个case语句只有一个入口标号,并不能确定执行的终止点,所以需加break,否则将执行到switch结构的结束点
当若干分支需要执行相同操作时,可以使用多个case分支共用一组语句
循环结构
do{}while();while(){}
循环体中要包含改变循环条件表达式的语句,否则便会造成无限循环
for
其他控制语句
break、continue、return
郑莉:例2-6,例2-9
面向对象程序设计
基本特点
抽象
概念:指对具体问题(对象)进行概况,抽出一类对象的公共性质并加以描述的过程
数据抽象:描述某类对象的属性和状态
行为抽象:描述某类对象的行为或功能特征
概念:指对具体问题(对象)进行概况,抽出一类对象的公共性质并加以描述的过程
封装
概念:将抽象得到的数据和行为(或功能)相结合,形成一个有机的整体,形成“类”
数据和行为(功能)分别对应类的数据成员(属性)和函数成员
对成员访问权限合理控制,使不同类之间的相互影响减少到最低限度,进而增强数据的安全性和简化编程
封装为一个可重用的模块,编程时可有效利用已有的成果
通过外部接口,依据特定的访问规则,就可以使用封装好的模块。使用时可以不必了解类的实现细节
继承
特殊与一般的关系,允许程序员在保持原有类特性的基础上,进行更具体、更详细的说明
多态
概念:多态性是指一段程序能够处理多种类型对象的能力
4种形式:强制多态(类型转换)、重载多态(函数重载)、类型参数化多态(函数模板、类模板)、包含多态(虚函数)
类和对象
(封装性)
(封装性)
类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述
类成员的访问控制
公用类型(public)、私有类型(private)、保护类型(protected)
公用类型成员定义了类的外部接口
私有成员只能被本类成员函数和友元访问。如果私有成员紧接着类名称,则关键字private可以省略
保护成员,给派生类提供一些特殊的访问属性
对象
定义对象示例:Clock myClock;//调用无参构造函数
构造函数
在对象被创建的时候将被自动调用
没有写构造函数,编译器会自动生成一个隐含的默认构造函数,参数列表和函数体皆为空
调用顺序:基类构造函数(按继承时声明顺序,从左到右)>派生类新增的成员对象初始化(声明顺序)>派生类构造函数体中的内容
析构函数
在对象的生存期即将结束的时刻被自动调用,不接收任何参数,没有返回值
用于完成对象被删除前的一些清理工作,示例:~Clock(){...}
没有写析构函数,编译器会自动生成一个隐含的默认析构函数,函数体为空
调用顺序:自身析构函数体>基类析构函数
类的成员函数
函数的原型声明要写在类体中,原型说明了函数的参数表和返回值类型。函数的具体实现写在类定义之外
实现时,与普通函数不同,类的成员函数名需要用类名来限制,示例:Clock::ShowTime
带默认形参值的成员函数,其默认值,一定要写在类定义中,而不能写在类定义以外的函数实现中
内联成员函数(了解)
隐式声明:将函数体直接放在类体内
显式声明:采用关键字inline显示声明,示例:inline void Clock::showTime(){...}
成员函数包括构造函数(含复制构造函数)、析构函数、私有函数和公有函数四种(友元函数则不属于成员函数)
类的静态成员
静态成员是解决同一个类的不同对象之间数据和函数共享问题
采用static关键字声明
静态数据成员
类属性是描述类的所有对象共同特征的一个数据项,对于任何对象示例,它的属性值是相同的
通过类名对他进行访问,一般的用法是“类名::标识符”
静态数据成员需要在类定义之外再加以定义(单独分配空间)
静态函数成员
通过类名或对象名来调用,一般用类名
静态成员函数可以直接访问该类的静态数据和函数成员。
类的友元
友元关系,提供了一种数据共享的机制,就是一个类主动声明哪些其他类或函数是它的朋友,进而给它们提供对本类的访问特许
友元函数
概念:友元函数是在类中用关键字friend修饰的非成员函数,在它的函数体中,可以通过对象名访问类的私有和保护成员
友元类
友元类,是实现类之间数据共享的一种途径,
若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员
若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员
第一,友元关系是不能传递的
第二,友元关系是单向的
第三,友元关系不能被继承
继承与派生
(继承性)
(继承性)
最高层是抽象程度最高的,最下层是最为具体的
语法:class 派生类名 : 继承方式 基类名1, 继承方式 基类名2, ..., 继承方式 基类名n { ... }
继承方式
继承方式关键字:public protected private。未显式指定时,默认private
公有继承:基类的公有成员和保护成员的访问属性在派生类中不变,而基类的私有成员在派生类中不可直接访问
保护继承:基类的公有成员和保护成员都以保护成员身份出现在派生类中,而基类的私有成员在派生类中不可直接访问
私有继承:基类的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可直接访问
基类的构造函数和析构函数是不能被继承的
多继承:一个派生类,可以同时继承多个基类,这种情况称为多继承。
单继承:一个派生类只有一个直接基类的情况,称为单继承。
单继承:一个派生类只有一个直接基类的情况,称为单继承。
改造基类成员
一个是基类成员的访问控制问题,主要依靠派生类定义时的继承方式来控制
另一个是对基类数据或函数成员的覆盖或隐藏。
类型兼容性规则
概念:类型兼容性规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代
在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员
就算派生类存在同名覆盖,派生类对象作为基类对象使用时,将调用基类中同名成员。除非作为虚函数,被覆盖
派生类的构造和析构函数
派生过程中,构造函数和析构函数都不被继承
派生类的构造函数只负责对派生类新增的成员进行初始化,对所有从基类继承下来的成员,其初始化工作由基类的构造函数完成。
同样,对派生类对象的扫尾、清理工作也需要加入新的析构函数
同样,对派生类对象的扫尾、清理工作也需要加入新的析构函数
构造派生类的对象时,要对基类的成员对象和新增成员对象进行初始化
未定义构造函数,系统调用默认构造函数之前,会调用基类默认构造函数
语法:派生类型名::派生类名(参数表):基类名1(基类1初始化参数表),...,基类名n(基类n初始化参数表),成员对象名1(成员对象1初始化参数表),...,成员对象名m(成员对象m初始化参数表){ ... }
派生类构造函数执行的一般次序如下:
1. 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右)
2. 对派生类新增的成员对象初始化(构造函数初始化列表),调用顺序按照它们在类中声明的顺序
3. 执行派生类的构造函数体中的内容
1. 调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右)
2. 对派生类新增的成员对象初始化(构造函数初始化列表),调用顺序按照它们在类中声明的顺序
3. 执行派生类的构造函数体中的内容
复制构造函数
如果没有编写复制构造函数,编译系统会在必要时自动生成一个隐含的复制构造函数,这个隐含的复制构造函数会自动调用基类的复制构造函数,然后对派生类新增的成员对象一一执行复制(浅复制)
如果要为派生类编写复制构造函数,一般需要为基类相应的复制构造函数传递参数
示例:Derived::Derived(const Derived &v) : Base(v){...}
析构函数
只要在函数体中负责把派生类新增的非对象成员(申请的动态内存,网络连接等需要手动管理的资源)的清理工作做好就够了
系统会自己调用基类及对象成员的析构函数来对基类及对象成员进行清理
执行次序和构造函数正好完全相反
派生类成员的标识和访问
如果存在两个或多个具有包含关系的作用域,在内层声明了同名标识符,则外层标识符在内层不可见,这时称内层标识符隐藏了外层同名标识符,这种现象称为隐藏规则
如果派生类中声明了与基类成员函数同名的新函数,即使函数的参数表不同,从基类继承的同名函数的所有重载形式也都会被隐藏
作用域分辨符:"::",它可以用来限定要访问的成员所在类的名称,示例:d.Base1::fun();//访问B1基类成员
using
一般功能是将一个作用域中的名字引用到另一个作用域中
还有一个非常有用的用法:将using用于基类中的函数,这样派生类中如果定义同名但参数不同的函数,基类的函数不会被隐藏,两个重载的函数将会并存
虚基类
将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个副本,同一个函数名也只有一个映射
语法:class 派生类名:virtual 继承方式 基类名
多态性
多态是指同样的消息,被不同类型的对象接收时,导致不同的行为。(所谓消息是指对类的成员函数的调用)
面向对象的多态性可以分为4类:重载多态,强制多态,包含多态和参数多态
使用多态时注意:
基类的指针可以指向派生类对象,基类的引用可以作为派生类对象的别名,但基类的对象却不能表示派生类的对象
郑莉P319
基类的指针可以指向派生类对象,基类的引用可以作为派生类对象的别名,但基类的对象却不能表示派生类的对象
郑莉P319
示例:Derived d; //定义派生类对象
Base * ptr = &d; //基类指针ptr可以指向派生类对象
Base &ref = d; //基类引用ref可以作为派生类对象的别名
Base b = d; //调用Base的复制构造函数用d构造b,b的类型是Base而非Derived
Base * ptr = &d; //基类指针ptr可以指向派生类对象
Base &ref = d; //基类引用ref可以作为派生类对象的别名
Base b = d; //调用Base的复制构造函数用d构造b,b的类型是Base而非Derived
多态的实现
编译时多态
编译的过程中确定了同名操作的具体操作对象
运行时多态
程序运行过程中才动态确定操作所针对的具体对象
运行过程中的多态需要满足3个条件:
1. 类之间满足赋值兼容规则
2. 要声明虚函数
3. 由成员函数来调用或者是通过指针、引用来访问虚函数
1. 类之间满足赋值兼容规则
2. 要声明虚函数
3. 由成员函数来调用或者是通过指针、引用来访问虚函数
运算符重载
重载为类的非静态成员函数
示例:Complex operator + (const Complext &c2) const;
重载为非成员函数
形参表中形参从左到右的顺序就是运算符操作数的顺序
示例:ostream & operator << (ostream &out, Complex &c){ ... }
语法:返回类型 operator 运算符(形参表){ ... }
虚函数
虚函数必须是非静态的成员函数
语法: virtual 函数类型 函数名(形参表);
虚函数声明只能出现在类定义中的函数原型声明中,而不能在成员函数实现的时候
其原型与基类必须完全相同(即返回类型、函数名、参数个数、类型及顺序一样),否则系统将认为派生类中的函数是重载的,而非虚函数;
如果仅有返回类型不同,那么编译将出错;
如果仅有返回类型不同,那么编译将出错;
派生类的虚函数还会隐藏基类中同名函数的所有其他重载形式
当基类被构造时,不会调用派生类的虚函数(对象还不是一个派生类的对象)
当基类被析构时,不会调用派生类的虚函数(对象已经不再是一个派生对象了)
当基类被析构时,不会调用派生类的虚函数(对象已经不再是一个派生对象了)
基类的指针可以指向派生类的对象,基类的引用可以作为派生类对象的别名,但基类的对象却不能表示为派生类的对象
虚函数的默认形参值只能来自基类的定义,派生类不要重新定义不同的值
虚析构函数
在C++中,不能声明虚构造函数,但可以声明虚析构函数
如果一个类的析构函数是虚函数,则由它派生而来的所有子类的析构函数都是虚函数
目的:保证使用基类类型的指针就能够调用适当的析构函数针对不同的对象进行清理工作,避免滞留在内存中
如果基类里有虚函数,定义了基类指针指向派生类,就会需要定义基类虚析构
纯虚函数
语法:virtual 函数类型 函数名(形参表)=0;//注:基类中可以无需给出函数的实现部分
如果析构函数声明为纯虚函数,必须给出它的实现,因为派生类的析构函数体执行完后需要调用基类的纯虚函数
纯虚函数不同于函数体为空的虚函数,纯虚函数根本没有函数体;
前者所在的类是抽象类,不能直接进行实例化,而后者所在的类是可以实例化的;
前者所在的类是抽象类,不能直接进行实例化,而后者所在的类是可以实例化的;
抽象类
概念:带有纯虚函数的类是抽象类
抽象类不能实例化
抽象类派生出新的类之后,如果派生类给出所有 纯虚函数 的函数实现,则这个派生类就可以实例化
派生类与基类的纯虚函数具有相同的名称、参数和返回值类型,由系统自动判断确定其为虚函数
多态类型
设计多态类型的一个重要原则是,把多态类型的析构函数设定为虚函数
Tips:多动手写代码 ,掌握面向对象程序设计
常用算法
分类(排序)算法
插入排序
基本思想:每一步将一个待排序元素按其关键字值的大小插入到已排序序列的适当位置上,直到待排序元素插入完为止
选择排序
基本思想:每次从待排序序列中选择一个关键字最小的元素(当需要按关键字升序排列时),顺序排在已排序序列的最后,直至全部排完
交换排序(冒泡)
基本思想:两两比较待排序序列中的元素,并交换不满足顺序要求的各对元素,直到全部满足顺序要求为止
检索(查找)算法
无序数据序列的查找:顺序查找(遍历算法)
有序数据序列的查找:二分法(折半查找)
基本思想:对于已按关键字排序的序列,经过一次比较后,可将序列分割成两部分,
然后只在有可能包含待查元素的一部分中继续查找,并根据试探结果继续分割,逐步缩小查找范围,直至找到或找不到为止
然后只在有可能包含待查元素的一部分中继续查找,并根据试探结果继续分割,逐步缩小查找范围,直至找到或找不到为止
遍历算法
一维数组和二维数组的遍历
链表的遍历
while(node != NULL){ ...; node = node->next; }
文件的遍历
示例:while(file){ file.read(reinterpret_cast<char *>(&v), size); ...;}
while(getline(file, line)){ cout << line << endl; }
while((ch=file.get()) != EOF){ ... }
while(getline(file, line)){ cout << line << endl; }
while((ch=file.get()) != EOF){ ... }
UML类图
类图,它属于静态结构图的一种,展示的是软件模型的静态结构、类的内部结构以及和其他类的关系
UML语言中,分3端矩形来表示一个类。分别放置类名(抽象类通过书写斜体类名称标识)、数据成员、函数成员
UML语言,表示一个对象,对象的名字要加下划线
UML数据成员语法
[访问控制属性(+ - #)] 名称 [重数] [: 类型] [=默认值] [{约束特征,例如 只读}],示例:-hour : int
静态数据成员,通过在数据成员下方添加下划线表示
常数据成员
UML函数成员语法
[访问控制属性] 名称 [(参数列表)] [: 返回类型] [{约束特征}],示例:+setTime(newH : int, newM : int, newS : int=0) : void
静态函数成员,通过在函数成员前添加<<static>>构造型来表示,示例:<<static>> + showCount() : void
友元函数,通过在函数前添加<<friend>>构造型表示
友元函数
友元类
常成员函数,通过在成员函数前添加<<const>>构造型表示
虚函数,通过在成员函数前添加<<virtual>>构造型表示
纯虚函数,通过在成员函数前添加<<abstract>>构造型表示
关系
依赖关系
表明一个类使用另一个类作为它的函数成员的参数时,使用依赖关系
图形:带箭头的虚线
作用关系-关联
表述一个类的对象和另一个类的对象之间相互作用的连接
重数:“重数A”决定了类B的每个对象与类A的多少个对象发生作用
图形:不带箭头的实线
包含关系(一种特殊的关联)
聚集
表示类之间的关系是整体与部分的关系,“包含”、“组成”、“分为...部分”等都是聚集关系
图形:空心菱形(连接整体)+实线
组合
部分与整体共存,如整体不存在了,部分也会随之消失,这称为组合
组合是一种简单聚集形式,但是具有更强的拥有关系
图形:实心菱形(连接整体)+实线
继承关系-泛化
图形:空心三角箭头+实线
Tips:详细图形参考教材或网络
收藏
0 条评论
下一页