您的当前位置:首页正文

c++教案完整稿

2021-01-02 来源:易榕旅网


《c++语言程序设计》授课教案

VC++集成开发环境

集成开发环境:程序编辑、编译、连接、调试及运行的环境。在这个环境中提供了软件代码自动生成和可视化的资源编辑功能以及强大的类(class)管理功能。

VC++最主要的特点是可视化的编程环境和支持面向对象的编程技术。 集成环境具体介绍: 集成环境示意: 项目工作区 工具栏: 菜单栏: 项目工作区:

集成开发环境的应用示例:利用APPWIZARD来创建一个简单的应用程序。 附:一个工程中的文件类型说明:

*.DSW 在VC中级别最高,称为项目工作区文件 *.DSP 每一个工程都有自己的DSP文件

*.OPT 工作区选项文件,存储本地计算机的有关配置信息 *.CLW 存放应用程序中用到的类和资源

README.TXT 每一个应用程序都有一个README.TXT *.H和*.CPP 头文件和源文件 *.RC 资源文件 *.RC2资源文件

*.ICO 以及*.BMP等 具体的资源文件

第一章 C++语言基础

一、基本概念

(一)面向对象计算的基本特征

1、对象:由信息和对它进行处理的描述所组成的包;或者说对象代表着正在创建的系统中的一个实体。对象通过消息与另一个对象传递信息。

2、类:是所有对象的共同的行为和不同状态的集合体。 3、类的继承:

4、消息:对某个对象进行处理的说明(对函数的调用)。

5、方法:对对象接受了某一个消息后所采取的操作的描述

6、类的封装:封装是把一类对象的状态(用数据表示)和方法(用函数表示)封闭起来,装入对象中,形成一个能动的实体。 7、类的多态:

(二)c++对面向对象程序设计方法的支持 1、c++支持数据封装

2、c++类中包含私有、公有、保护成员 3、c++中通过发送消息来处理对象 4、c++中允许友元破坏封装性 5、c++中允许函数和运算符重载 6、c++支持继承性 7、c++支持动态联编

一个简单的C++程序实例:

定义一个用来计算圆的面积的程序: #include const double pi=3.14; class Circle {

public:

int radius;

double calculate_area() { return pi*radius*radius; }

double calculate_perimeter() { return 2*pi*radius; } };

void main() {

Circle theCircle;

cout<<\"请输入圆半径: \"; cin>>theCircle.radius;

cout<<\"圆面积为: \"<cout<<\"圆周长为: \"<语句解释:#include预处理包含指令,其中iostream.h为C++提供的标准类库,它提供了输入输出流CIN和COUT及输入输出运算符》和《的定义。 (三)、c++程序的组成部分 1、预处理命令 2、输入和输出语句 3、函数 4、语句 5、变量 6、常量 7、注释:(1) /* */ ( 2 ) // 8、标识符

(四)、c++的词法规则 1、C++的标识符

标识符:在高级程序设计中,通常采用一定含义的名字来表示程序中的数据,以便能够按名字来访问数据,

这个名字叫标识符。

标识符的组成:有32个字符组成。(包括下划线,数字符号0—9,英文字母三种字符) 例如:name how_are_you Kill j78u l$op 2、注意事项:

1)标识符的第一个字符必须是英文字母或下划线 2)大小字母是不同的字符。

3)定义标识符时,要满足意义尽量明确的原则。

4)C++的关键字和保留字不能作为标识符(如INT、NEW、FOR、IF、CASE等) 附:C++的关键字如下:

ASM CONTINUE FLOAT NEW SIGNED TRY AUTO DEFAULT FOR OPERATOR SIZEOF TYPEDEF CASE DE GOTO FRIEND PRIVATE STATIC UNION BREAK DELETE PROTECTED STRUCT UNSIGNED CATCH DOUBLE IF PUBLIC SWITCH VIRTUAL CHAR ELSE INLINE REGISTER TEMPLATE VOLATILE CONST CLASS ENUM RETURN THIS EXTERN LONG SHORT THROW WHILE 二、C++程序的编辑、编译、及运行

1、单击主菜单中的FILE----NEW,选择TEXT FILE 2、输入源程序

3、编译:单击编译菜单中的编译命令 4、连接:单击编译菜单中的连接命令 5、运行:单击编译菜单中的运行命令

第二章 C++的基本数据类型和表达式

一、C++的标识符

1、标识符:在高级程序设计中,通常采用一定含义的名字来表示程序中的数据,以便能够按名字来访问数据,这个名字叫标识符。

2、标识符的组成:有32个字符组成。(包括下划线,数字符号0—9,英文字母三种字符) 例如:name how_are_you Kill j78u l$op 3、注意事项: 1)、标识符的第一个字符必须是英文字母或下划线 2)、大小字母是不同的字符。 3)、C++的关键字和保留字不能作为标识符(如INT、NEW、FOR、IF、CASE等) 4)、给标识符命名时,要满足意义尽量明确的原则 5)、附:C++的关键字如下

ASM CONTINUE FLOAT NEW SIGNED TRY AUTO DEFAULT FOR OPERATOR SIZEOF TYPEDEF CASE DE GOTO FRIEND PRIVATE STATIC UNION BREAK DELETE PROTECTED STRUCT UNSIGNED CATCH DOUBLE IF PUBLIC SWITCH VIRTUAL CHAR ELSE INLINE REGISTER TEMPLATE VOLATILE CONST CLASS ENUM RETURN THIS EXTERN LONG SHORT THROW WHILE 二、C++中的数据类型:

1、基本类型包括:VOID无值型、CHAR字符型、INT整形、FLOAT浮点、DOUBLE双精度型,以及他们的各种变形形式SHORT、LONG、SIGNED有符号、UNSIGNED无符号等(注意:对于INT型数据如果其前面加上修饰符,则INT可以省略)。

2、派生类型包括:指针、引用、数组、枚举、函数、结构体、公用体和类等。 举例:

//程序清单2.3 ex2-3.cpp #include void main() {

int a; //定义整型变量 a; int year=2001; //定义整型变量 year,初始值为2001 float f1 = 3.1415; //定义浮点型变量 f1,初始值为3.1415 double d1,d2; //定义双精度型变量 d1和d2

char vchar = 'a'; //定义字符型变量vchar,初始值为'a' signed int a; short int b; unsigned int c;

unsigned long int d „„ //程序其余部分 }

注意:1、CHAR 定义的变量只能存储单个字符,而不能存储字符串,如CHAR CHI=“CHINA”是错误的,若要存放字符串,在C++中常用字符数组。

2、无值型VOID:用于表达一种特殊的函数返回的数据类型。

三、常量: (一):整形常量 1、十进制数: 2、八进制数 3、十六进制数: (二)、浮点型常量 1、小数表示法: 2、科学表示法:

3、注意:单精度数据与双精度数据的区别。 (三)、字符常量

1、用该字符的图形字符来表示。(可打印字符) 2、转义序列表示法:(用 / 加字符的ASCII码来表示) (四)、字符串常量:

注意:1、所有的字符串常量系统都会自动地在其后面加上\\0作为其结尾标志。 2、字符常量与字符串常量的区别。 (五)、符号常量

1、常量的定义: CONST 类型 标识符=常量 例如:CONST INT F=0

CONST DOUBLE I=0.12 CONST FLOAT PI=3. 14 CONST CHAR VCH=‘A‘

2、常量定义好了以后,可以用常量标识符代替常量 例如:

#include const double PI=3.14; void main() {

int radius;

cout<<\"请输入圆半径:\"; cin>>radius;

out<<\"圆面积为:\"<3、常量的定义也可以用#DEFINE命令来定义。例如: #include #define PI 3.14; void main() {

int radius;

cout<<\"请输入圆半径:\"; cin>>radius;

cout<<\"圆面积为:\"<4、在C++中定义了一些以“\\‖开头的特殊字符常量。如下表:

含义 字符常量形式 \\n 换行符

\ 水平制表

\\v 垂直制表

\\b 退格

\\r 回车 \\f 走纸换页 \\a 响铃

\\\\ 反斜杠

\\? 问号

\\‘ 单引号

\\‖ 双引号 NULL字符 \\0

四、变量: 1、变量的定义

格式:数据类型 变量名 例如:INT A

CHAR VCH FLOAT P

2、变量的初始化:

格式:数据类型 变量名=常量 例如: INT A=2

CHAR VCH=‘J’ FLOAT P=2.1 注意:1)、初始化只能对一个变量进行, 例如:FLOAT X,Y,Z=12.34

2)、先定义,后使用。 3)、注意各种数据类型变量的默认值情况。

数组

一、一维数组 1、定义:

格式:数据类型 数组名[常量表达式] 例如:int a[100] float b[10]

2、元素组成:有一个定义好的数组a[n],它的元素分别可以用a[0], a[1], a[2], a[n-1]来表示。 注意:a.数组的下标只能用方括号表示,并且它的值是丛 0开始的。 b.常量表达式中只能包括常量,不能包括变量,例如 int n=10 int a[n]是错误的。

c、在一维数组中数组名是该数组在内存中首地址。 3、引用

格式:数组名 [下标表达式] 例如: int a[100],I=5

a[5]=32

f=b [I*3+8] +3.2

注意:一次只能引用单个数组元素,不能引用整个数组。 4、举例

用一维数组编写程序,计算用户输入的10个数的和。 #include

const n=10; void main() {

int i,sum=0; int a[n];

for (i=0;i>a[i]; cout<<\"\\n\"; }

for (i=0;icout<<\"和为:\"<将长度为n的一维数组的数据进行两两对换。 #include const n=9; void main() {

int i,temp; int a[n];

cout<<\"请输入\"<>a[i]; }

cout<<\"\\n\";

for (i=0;icout<<\"对换后的结果为:\\n\"; for (i=0;i二、多维树组(下标的个数称为数组的维数) 1、定义:

格式:类型 数组名 [常量表达式] [常量表达式] 例如: float a[2] [3]

在二维数组中,元素的排列顺序是按行排列的。例如数组a[2][3]的元素的排列顺序为:

a[0][0]---a[0][1]---a[0][2]-- a[1][0]---a[1][1]---a[1][2]

2、多维数组的初始化

1)将数组的初始值写在一对大括弧内,按照数组元素的排放次序依次向数组元素赋初值。例如: int a[4][2]={0,1,2,3,4,5,6,7}

注意:1、初始值的个数也可以小于数组元素的个数,剩余的数组元素的值将取0

2、初始化时,数组元素的个数要大于初始值表中数据的个数。否则将出现编译错误。 2)按行给二维数组赋值。例如: a[4][2]={{0,1},{2,3},{4,5},{6,7}} 3、多维数组的引用

格式:数组名 [下标表达式] [下标表达式]

例如:a[4] [5]=34

注意:在使用数组元素时,数组的下标的值应在预定义的大小范围内。例如:int a[4] [4] a[4] [4]=5是错误的。 4、三维数组(略) 5、例:

使用二维数组编写一个程序,从键盘接收由用户输入的5*5距阵,并把这个距阵打印出来 #include const n=5; void main() {

int i,j; int a[n][n];

cout<<\"请输入5*5矩阵的值:\\n\"; for (i=0;i>a[i][j];

cout<<\"打印5*5矩阵如下:\\n\"; for (i=0;i使用二维数组编写一个程序,能够打印出以下的杨辉三角形。 #include const n=9; void main() {

int i,j; int a[n][n];

for (i=0;ifor (i=0;i三、字符数组(用来存放字符的数组称为字符数组,数组中的每一个元素只能存放一个字符。) 1、字符数组的定义和初始化

定义:格式:CHAR 数组名 [常量表达式] 例如:CHAR A[10] 2、初始化:

a、一般在定义时,就完成初始化。 例如:CHAR A[4]={‘G’,‘C’,‘’,‘F’} b、通过字符串常量来初始化。 例如CHAR A[5]={“abcd”}

3、举例:在程序中初始化字符串,然后输出。 #include void main() {

char a[12] = {'G', 'o', 'o', 'd', ' ', 'm', 'o', 'r', 'n', 'i', 'n', 'g'}; int i;

cout<<\"输出字符串:\"; for (i=0;i<12;i++) { cout<cout<<\"\\n\"; }

四、字符串的处理

字符串:是一组字符数据,它和字符数组的区别在于,它一般作为整体来引用,在C++中,没有专门提供字符串类型,而是将字符串存放在字符数组中来使用。

字符数组的初始化可以通过字符串常量来赋值。 例如: char a[ ]={―good morning!‖}或 char a[ ]=―good morning!‖ 注意:

1、系统要求每个字符串后面都以‘\\0’为结束标记。所以字符数组的初始化通过字符串常量来赋值与前面的初始化是有区别的。

2、一维字符数组可以存放一个字符串,多维字符数组可以存放多个字符串。 Char ss[2][4]={{‗a‘, ‗b‘, ‗c‘, ‗\\0‘},{‗b‘, ‗d‘, ‗v‘, ‗\\0‘}} 附:字符串的处理函数:

1、s t r c a t (字符数组1,字符数组2):连接两个字符数组中的字符串,并把结果放到字符数组1中。例如: char a[ ]={―today is ―} char b[ ]={―Monday‖} strcat (a , b)

执行完后,字符数组1的内容为: today is monday

2、s t r c p y (字符数组1 , 字符串2 ,整数n ):字符串拷贝函数,将字符串2的前n个字符拷贝到字符数组1 中,若省略n,则拷贝所有字符。例如: char fake[20]

strcpy (fake , ―I love this game!‖);

3、s t r c m p(字符串1 , 字符串2):比较两个字符串的大小。比较的规则如下:对两个字符串自左向右逐个字符相比,直到遇到不同的字符或字符串的结束标记为止。 s t r c m p的返回值的情况如下: 字符串1=字符串2 , 返回0

字符串1>字符串2 , 返回值为正整数 ,该整数是两个字符串中第一个不同字符的ASCⅡ码的差值。 字符串1<字符串2 , 返回值为负整数 ,该整数是两个字符串中第一个不同字符的ASCⅡ码的差值。 4、s t r l e n(字符数组):计算字符串的长度,长度不包括字符串的结束标记。 Char fake[20];

Strcpy (fake , ―I love this game!‖); Cout <五、字符数组举例:编程实现合并用户输入的两个字符串,并计算合并后的字符串的长度。 #include #include void main()

{ }

char a[50],b[50];

cout<<\"请输入字符串1:\"; cin>>a; cout<<\"\\n\";

cout<<\"请输入字符串2:\"; cin>>b; cout<<\"\\n\"; strcat(a,b);

cout<<\"合并字符串:\"<cout<<\"合并字符串长度:\"<枚举类型

一、枚举是一种构造的数据类型,它是若干个有名字的整形常量的集合。 二、枚举类型(模式)的定义:

1、格式: enum [枚举名] { [枚举表] };

enum day {sum ,mon ,tue ,wed ,thu ,fri ,sat}

2、上述格式中的每个枚举符是一个用标识符表示的整形常量。

3、枚举符的赋值: 可以直接赋值,但在默认情况下,最前面一个为0,接着一个为1,后一个总是前一个的值加1。

Enum day { sum=3 , mon=5 , tue , wed , thu , fri} 三、枚举型变量的定义:

1、格式: enum [枚举名] [枚举变量表]; enum day di , d2 ,d3; 四、枚举变量的赋值:

1、枚举变量的值是该枚举变量所属的枚举模式的枚举表的某个枚举符。 enum day di , d2 ,d3; d1=mon; d2=sat;

2、注意不能直接把整形数值赋给枚举变量。

D3=7;

指针与引用

一、 指针的概念:

指针:是用来存放某个变量的地址值的一种变量。 指针变量:用来专门存放其他变量的地址的变量。 二、 指针变量的定义:

1、格式: 数据类型 * 变量; 例如: int *p1, *p2; 2、注意:

1).指针变量中只能存放地址(指针),不要将一个整形变量(或其他非地址类型的数据)赋给一个指针变量。

int *p1, *p2; p1=3;

2).指针变量里存放的哪个变量的地址值,就说指针指向哪个变量(分析)。

Int a=5 , *p; *p=&a;

3).指针的类型是它所指向的变量的类型,而不是指针本身数据值的类型(指针指向的数据类型有多种)。

int *p1, *p2; int (*p1)[6] int (*p1)() int * *p1

float *p1

4).在定义一个指针后,系统会给指针分配一个内存单元,各种不同类型的指针所被分配的内存空间的大小是相同的。

三、 指针的赋值

任何一种类型的指针所赋的值都只能是内存的地址值。但是不同类型的指针的内存地址值是不尽相同的。 1、一般变量、数组元素等其地址值都表示为变量名前加运算符&。

Int a , b[10]; Int *p1 , *p2; p1=&a; p2=b[4];

2、数组的地址值使用该数组的数组名来表示。

1)、Int a , b[10]; Int *p1;

P1=b; //表示p1指向数组b的首元素。

2)、 int b[5][6]; int (*P) [6];

P=b; //表示p指向数组b的第0行。

3)、三维数组的情况。

3、函数的地址值可用该函数的名字来表示。

Int xinguan (int xx); Int (*p) ( );

P=xinguan; //表示p指向函数xinguan在内存中的入口地址。

注意:1)、在c++中,指针必须赋值以后才能引用。 2)、一个暂时不用的指针,为了安全,可以将0值赋给该指针,是它称为空指针。 四、 指针的运算符

与指针有关的运算符: & 取地址运算符 * 指针运算符

例如:&a为变量a的地址,*p为指针变量p所指向的变量。 例如:采用调整地址的方法,输入两个整数。 #include void main(void) { int a,b; int *p0,*p1,*p_temp; cout<<\"请输入整数a:\"; cin>>a; cout<<\"\\n\"; cout<<\"请输入整数b:\"; cin>>b; cout<<\"\\n\"; p0=&a; p1=&b; if(a五、指针与数组的关系。 (一)、数组元素的指针表示法 1、一维数组元素

格式:如果定义好了一个数组a[n],那么它的元素可以用*(a+I)I=0,1,2,3………n-1来表示。 2、二维数组元素

格式:如果定义好了一个数组a[n] [m],那么它的元素可以用(*(a+I)+j) I=0,1,2,3………n-1,j=0,1,2,3………m-1来表示。 3、三维数组元素

(二)举例:

1、#include void main() {

int a[5] = {5, 4 , 3 , 2 , 1}; int I , j; I=a[0]+a[4];

J=*(a+2)+*(a+4); cout<2、#include void main() {

char s2[ 5] = {'G', 'o', 'o', 'd', '\\0 '}; char s1[] = ―abcde‖; char *p=s1;

cout<cout<3、#include void main() {

int b[ ][3] = {{1,2,3} , {4} ,{5,6}}: b[0][2]=7; b[1][2]=8;

cout<<* *b<<‖\‖<<* *(b+1)<<‖\‖<<*(*(b+1)+2)<六、引用

1、定义:变量的别名

使用格式:<类型> & <引用名> (<变量名>)或

<类型> & <引用名>= <变量名>

如:int a=3;

int &m=a;

引用定义好了以后,所有在引用上所施加的操作,实质上就是在被引用者上的操作。并且也可以将一个引用赋给某个变量。

2、注意:引用在使用之前,必须先初始化。

运算符与表达式

一、运算符与表达式

1、表达式:用运算符和括号将操作数连接起来的、符合C++规则的式子,叫做C++表达式. 2、举例:

//程序清单 ex2-4.cpp #include #include

void main() {

double i,j; int a;

i = sqrt(3.0); j = sin(0.5); a = (5*5)%3;

cout<<\"计算结果如下:\"<<\"\\n\"; cout<<\"i = \"<3、C++的运算符总结: 运算符 作用 运算符 作用 运算符 作用 :: 作用域分辨 DELETE 撤消 > . 成员选择 DELETE[] 撤消数组 >= -> 成员选择 (数据类型) 强制转换 = = [] 下标 .* 成员节 != () 函数调用及值结构 ->* 成员节 & SIZEOF 对象及类型大小 * 乘 ^ -- 前或后减量 / 除 | ~ 取补 % 取模 && ! 非 + 加 || - 单目减 - 减 ?: + 单目加 << 左移位 = & 取地址 >> 右移位 *= * 指针 < /= NEW 创建 <= %= += >>=和<<= &= |= ^= , 二、运算符的具体介绍: 1、二元算术运算符(* / + - % )

注意:余数=<操作数1> - <操作数2> * <整商> (1)、例如:5%3=

3%5= 3%3= 6%3=

2、算术运算符与赋值语句组合使用形成的复合运算符的使用: 复合运算符有:+= 作用:a+=b 相当于 a=a+b 例如:复合运算符的应用: #include Void main( ) {

int a,b;

a=3;b=2; cout<<‖a=‖<3、注意++I , - - I 与I++ , I- - 的区别: #include

— = *= /= %=

void main() {

int i=5;

cout<<\"计算结果如下:\"<<\"\\n\"; cout<<\"i++ = \"<cout<<\"++i = \"<<++i<<\"\\n\"; }

4、关系运算符

关系运算符:> >= < <= = = !=

优先级;前四种运算符优先级相同,但高于后两种,六种关系运算符的优先级低于算术运算符,高于赋值运算符

例如: a>b!=c 等效于 c>a+b 等效于

a= =ba=b>c 等效于 5、逻辑运算符

逻辑运算符:&& || !

优先级:|| 和&&的优先级低于关系运算符,而!的优先级高于关系运算符,同时高于算术运算符,其中逻辑运算符的优先级为:!---&&----||

例如:(a>b)&&(x>y)

在实际应用中,可以用逻辑表达式来表达复杂的条件。 6、条件运算符与条件表达式

格式:表达式1 ? 表达式2 :表达式3

操作:如果表达式1为真,则条件表达式的值为表达式2的值,如果表达式1为假,则条件表达式的值为表达式1的值。

例如:a>0 ? 1:(a<0? –1:0) max=(a>b) ? a : b

优先级:条件运算符的优先级高于赋值运算符,但比关系运算符和算术运算符都低。 具体应用:

#include Void main( ) {

char ch; cin>>ch;

ch=(ch>=‘A‘&&ch<=‘Z‘)? (ch+32):ch; cout<三、表达式中的类型转换

1、隐式转换:在双目运算中,要求两个操作数的类型一致,如果不一致,则转换成高精度的类型。 2、强制转换 1)、显式强制转换 格式:(类型标识符)或者 类型标识符(表达式) 例:int (3.5)

注意:a、此种方式是不安全的 double a=6.33; int b; b=(int ) a;

b、此种方式是一次性的 int a (3) , m double f;

f=5.33+ (double) a; m=a + f;

2)、隐式强制转换

a、在赋值语句中,一律将右边的值强制赋给左边的值

b、在函数有返回值的调用中,总是将return后面的表达式的类型强制转换为该函数的的类型。

四、类型定义

(一)通过关键字typedef来实现

1、格式: typedef <已有类型名> <新类型名表>;

typedef double wage ,bonus; wage weekly; bonus monthly;

新定义的类型名可以出现在标准类型名所能出现的任何位置。 (二)通过类型表达式来实现

1、类型表达式是由数据类型名与类型修饰符*或[ ]或&或( )所构成的式子。 2、类型表达式中符号的优先级

[ ]和( ) *和& 数据类型名 例如:

int * a[5]; //a为新的类型名,其类型为int * [5] int * d (double)

第三章 预处理和语句

一、预处理功能 1、文件包含命令 1)、格式:#include <文件名>或#include ”文件名”

其中:前种格式是指那些由系统提供的并放在指定子目录中的头文件;后种格式是指那些由用户自定义的并放当前目录或其他子目录中的头文件或其他源文件。 2)、一条文件包含命令只能包含一个文件,并且文件包含命令可以嵌套使用。 2、条件编译命令 1)、条件编译命令是用来定义某些编译内容要在满足一定条件下才参与编译的命令。 2)、格式: (1)、#ifdef <标识符> <程序段1> #else

<程序段2> #endif

附录:判断标识符是否被定义的方法:

defined (<标识符>) 结果为非0则已经定义 (2)、#ifndef <标识符> <程序段1> #else

<程序段2> #endif (3)、#if <常量表达式1> <程序段1> #eif <常量表达式1 > <程序段2> #eif <常量表达式1 > <程序段3> …….. #else

<程序段n+1> #endif

例1、#include #define A -10 void main () {

#if A>0

cout<<\"a>0‖<cout<<\"a<0‖<cout<<\"a= =0‖<}

例2、可以用条件编译命令来方便的跟踪、调试程序运行。 #define A 10 …….. #if A= =10

cout<<\"a>0‖<cout<<\"a<0‖< <字符串> 注意:a、宏名一般大写。

b、在c++中可以使用此种格式来定义符号常量。但请注意与const定义的区别。 c、标识符被宏定义之后,在取消之前不允许重新对它进行宏定义。 d、取消宏定义的方法: #udef <标识符>

(2)#define <宏名>(<参数表>) <宏体>

注意:a、在替换时,用参数表中的实参代替宏体中的字符。 #define ADD(x,y) x+Y ……..

s=ADD(5,6);

实际上s被替换成:s=5+3;

b、在定义时,宏名与左括号之间不能出现空格。

#define ADD (x+y) x+Y

例1、#include #define ADD(a,b) a+b void main( ) {

int x(5) , y(7) , s; s=ADD(x+1 , y-2); cout<<―s=―<例2、#include void main( ) {

int b(5) ; #define b 2

#define f(x) b*(x) int y(3);

cout<cout<流程控制方式中三种最基本的:顺序控制、条件分支控制和循环控制。

每一种控制都有赖于一种特定的程序结构来实现,因此也就有三种基本程序结构:顺序结构、条件分支结

构和循环结构。 (一)、顺序结构

顺序结构:通过安排顺序来决定程序流程的程序结构。如下图:由于―语句1‖在―语句2‖的前面因此先执行―语句1‖,后执行―语句2‖。

(二)、条件结构 1、if语句

格式:if(条件) 语句 1 else 语句 2

由格式可以看出,―else 语句 2‖部分可以没有。

格式含义是:如果条件成立就执行―语句1‖,否则就执行else后的―语句2‖,如图1所示;如果if语句中不包含―else语句2‖部分,则在条件不成立时什么也不做,如下图。(其中语句1和语句2不仅可以是一条语句,而且可以是复合语句)。

例1:输入一个年份判断是否闰年 #include void main(void) { int year;

bool IsLeapYear;

cout<<\"Enter the year:\"; cin>>year;

IsLeapYear = ((year %4 = = 0 && year %100! = 0)||(year %400 = = 0)); if (IsLeapYear)

cout<cout<2、if语句的嵌套

if 语句格式中的―语句1‖和―语句2‖本身也可以是 if 语句,从而构成嵌套的 if 语句。 格式:if (条件 1)

if (条件 2) 语句 1 else 语句2

else (条件 3) 语句3

注意:语句1、2、3、4可以是复合语句;每层的if 要与 else 配对,如果省略某一个 else ,便要用{ }

括起该层的 if 语句来确定层次关系。

例2: 比较两个数的大小 #include void main () {

int x,y;

cout<<\"Enter x and y :\"; cin>>x>>y;

if(x! =y)

if(x>y)

cout<<\"x>y\"<cout<<\"xcout<<\"x=y\"<3、if的多分支结构

格式:if (条件1) 语句1 else if (条件2) 语句2 else if (条件3) 语句3 „

else if (条件n) 语句n 〖else 语句n+1〗

原理:首先检测条件1,若满足则执行语句1;否则检测条件2,若满足则执行语句2;否则检测条件3,若满足则执行语句3„„如果所有的条件都不满足,则执行最后一个else后的语句(语句n+1),若没有该语句则什么也不做,如图。

例3:输入一个0~100分范围内的一个成绩,显示相应的等级:90~100——优;80~89——良;70~79——中;60~69——及格;60分以下——不及格。

源程序:#include void main() {

float score;

cout<<\"请输入成绩:\"; cin>>score;

if(score<0 || score>100) cout<<\"成绩必须在0~100之间!\";

else if(score<60) cout<<\"不及格\"<4、switch语句和switch多分支语句

switch语句的格式:

switch(整型表达式) {

case整型表达式1:语句序列1 case整型表达式2:语句序列2 …

case整型表达式n:语句序列n 〖default:语句序列n+1〗 }

例4:输入一个0~6的整数,转换成星期输出

源程序: #include void main(void) { int day; cin>>day; switch(day) {

case 0: cout<<\"Sunday\"<case 1: cout<<\"Monday\"<case 2: cout<<\"Tuesday\"<default: cout<<\"Day out of range Sunday . . . Saturday\"<(三)、循环结构 1、for循环

for语句的格式:

for(循环初始化;循环条件;循环参数调整)循环体

其中的循环条件应当是一个逻辑表达式,而循环初始化和循环参数调整都应当是具有副作用的表达式,其中循环参数还应当是一个能够影响循环条件的表达式。

说明:1、括号内的三项都可以省略,但分号不能省略。

2、循环条件如果省略,循环将无终止的进行下去。

例5:输入一个整数,求出它的所有因子

源程序:

#include void main(void) {

int n,k;

cout<<\"Enter a positive integer:\";

cin>>n;

cout<<\"Number \"<cout<2、while循环

while语句的格式:

while (循环条件) 循环体

由于这种结构先判断后执行,因此如果一开始循环条件就不成立的话,起循环体就一次也不执行。While语句更具一般性,一切用for语句实现的循环也可以用while语句实现。

do„while循环

do„while语句的一般格式:

do 循环体 while (循环条件)

由于这种结构先执行后判断,因此其循环体至少执行一次。

例6:

源程序:

#include void main() {

int i(1),a(0); for(;i<=5;i++) {

do{

i++; a++; }while(i<3); i++; }

cout<第四章 函数

函数是c++的基本特征,在c++编程中,常常把一个程序分成多个函数来实现。这样将有利于数据共享,节省开发时间,增强程序的可靠性和便于管理等。

一、函数的定义: 1、无参数函数的定义 格式:

类型标识符 函数名 ( ) //函数头 {

说明部分和语句部分 //函数体

}

例如: void display () {

cout<<‖this is a display message‖; }

2、有参数函数的定义 格式:

类型标识符 函数名 (形式参数表 ) {

说明部分和语句部分

}

举例: int sum (int x,int y, int z) {

return(x+y+z) }

注意:c++允许有“空函数”,例如:

类型标识符 函数名 (形式参数表 ) { }

二、函数的说明方法:

1、在c++中,函数的说明原则如下:如果一个函数定义在先,调用在后,调用前可以不必说明;如果一个函数调用在先定义在后,调用前必须说明。

2、说明的格式: < 类型 > < 函数名> (<参数表>); 3、#include void fun1( ) , fun2( ) , fun3( ) ; void main ( ) {

cout<<‖it is main‖<cout<<‖it is back in main‖<void fun1( ) {

cout<<‖it is in fun1‖<cout<<‖it is back in fun1‖<void fun2( ) {

cout<<‖it is in fun2‖<cout<<‖it is back in fun2‖<void fun3( ) {

cout<<‖it is in fun3‖<三、函数的调用 (调用函数是实现函数功能的手段): 1、调用格式: 函数名 (实际参数表);

实参的个数由形式参数的个数决定,实参是用来在调用函数时给形参初始化的。因此要求在函数调用时,实参的个数和类型要与形参的个数和类型是一致的。当然,参数可有可无,但小括号不能省。 2、按照函数在程序中的位置,调用形式可以分为:

把函数调用作为一个独立的语句。 如 PISPLAY() 函数出现在表达式中。 如AVERGE=SUM(A,B,C)/3 函数调用本身作为另一个函数的实际参数。如 M=AVERGE(SUM(A,B,C),N) 3、函数的调用注意:

如果使用标准函数或库函数,应用预处理指令先定义 函数调用是一种表达式,其表达式的值是函数的返回值。

函数的返回值是通过函数中的 RETURN语句获得的。其格式如下: ret u r n <表达式> 或ret u r n < > 四、调用方式: 1)、传值调用:在此种方式中,调用函数的实参用常量、变量值或表达式值,被调用函数的形参用变量。传值调用的实现机制是系统将实参拷贝一个副本给形参。传值调用的特点是形参值的改变不影响实参。 #include

void swap1 (int x , int y) {

int temp; temp=x; x=y; y=temp;

cout<<‖x=‖<void main ( ) {

int a(5),b(9); swap1(a , b);

cout<<‖a=‖<形参指针所指向的实参值来间接改变实参值。其特点是形参的改变影响实参。 #include void swap1 (int *x , int *y) {

int temp; temp=*x; *x=*y; *y=temp;

cout<<\"x=\"<<*x<<\"y=\"<<*y<void main() {

int a(5),b(9); swap1(&a,&b);

cout<<\"a=\"<

void swap1 (int &x , int &y) {

int temp; temp=x; x=y; y=temp;

cout<<‖x=‖<void main ( ) {

int a(5),b(9); swap1(a , b);

cout<<‖a=‖<提问:设计一个函数:exchange(x , y , z),当调用exchange(a ,b ,c)时,将a的内容设置给b,b的内容设置给c,c的内容设置给a。要求使用两种方法实现。 举例:用函数形式编写程序显示杨辉三角形: #include const n=9; void triangle() {

int i,j; int a[n][n];

for (i=0;ifor (i=0;icout<void main() {

cout<<\"打印杨辉三角形如下:\"<<\"\\n\"; triangle(); }

五、函数的参数

1、函数参数的求值顺序:在c++中没有规定在函数调用时实参的求值顺序,由编译器自行决定。在一般情况下,参数的求值顺序对程序的运行结果没有影响。但有时也会有影响。此时只需改变程序的书写顺序就可以去掉其二义性。

#include int add_int(int x ,int y) {

return x+y; }

void main () {

int x(4),y(6);

int z=add_int(++x,x+y); cout<可以改成:

…………… int x(4),y(6); int t=++x;

int z=add_int(t,x+y); cout<2、设置函数参数的默认值:

在c++语言中,允许在函数的说明或定义时给一个或多个参数指定默认值。但是要求在一个指定了默认值的参数的右边,不能出现没有指定默认值的参数。在函数调用时,当实参数目不足时,编译器将按同样的顺序用说明或定义中的默认值来补足所缺少的实参。

注意:当形参指定的默认值和实参指定的值同时存在时,实参的优先级高,但它们都低于全局变量的优先级。

#include int m(8);

int add_int(int x ,int y=7 , int z=m) {

return x+y+z; }

void main () {

int x(5),y(15),z(20); int s=add_int(x,y); cout<3、使用数组作函数参数的情况(3种情况结果相同,只是调用方式不同,因为它们都是形参和实参共用内存中的同一个数组)。 1)、形参和实参都用数组 2)、形参和实参都用对应数组的指针或者它们当中任意一个是指针。 3)、实参用数组名形参用引用

#include int a[8]={1,3,5,7,9,11,13} void fun(int b[ ],int n) {

for(int I=0;Ivoid main( ) {

int m=8; fun(a,m);

cout<六、内联函数

引入内联函数主要是解决时间、空间的开销与程序运行效率的平衡问题。函数调用会增加时间上的开销。引入内联函数会增加空间上的开销。

1、内联函数的方法:只需在函数头前加关键字inline即可 例:求1~10的平方 #include inline int fun(int x) {

return x*x; }

void main( ) {

for (int I=1;I<=10;I++) {

int p=fun(i);

cout<2、注意事项: 1)、在内联函数中不允许用循环和开关语句 2)、内联函数的定义必须出现在内联函数第一次被调用之前。

七、函数重载

函数重载是指同一个函数名可以对应着多个函数的实现。每种实现对应一个函数体,这些函数的名字相同,但是函数的参数的类型或者参数的个数不同。调用函数在调用被调用函数时,根据参数的类型来确定具体调用哪个函数。

1、参数类型上不同的函数重载 #include int add(int ,int);

double add(double ,double); void main( ) {

cout<int add(int x ,int y) {

return x+y }

double add(double x ,double y) {

return x+y

}

2、参数个数上不同的函数重载 #include int min(int a,int b);

int min(int a,int b,int c);

int min(int a,int b,int c,int d); void main( ) {

cout<int min(int a,int b) {

return aint min(int a,int b,int c) {

int t=min(a,b); return min(t,c); }

int min(int a,int b,int c,int d) {

int t1=min(a,b); int t2=min(c,d); return min(t1,t2); }

八、函数的嵌套调用

嵌套调用指的是在调用A函数的过程中,可以调用函数B,在调用B函数的过程中,还可以调用函数C…..。当C函数结束后返回到函数B,当B函数调用结束后返回到函数A。 例:#include const int k=4; const int n=6;

int sum_of_power(int k,int n); int power(int m,int n); void main( ) {

cout<<‖sum of‖<int sum_of_power(int k,int n) {

int sum=0;

for(int I=1;I<=n;I++) sum+=power(I,k); return sum; }

int power(int m,int n) {

int I,pro=1;

for(I=1;I<=n;I++) pro*=m; return pro; }

九、函数的递归调用

递归调用是指在调用一个函数的过程当中直接或间接的调用函数自身。(直接调用自身称为直接递归调用;间接调用自身称为间接递归调用) 1、递归调用的过程; 1)、递推阶段 2)、回归阶段

例:编程实现从键盘上输入一个数存入变量n中,求!。 #include long int fac(int n); void main( ) {

int n;

cout<<‖input a positive integer:‖;

cin>>n;

long fa=fac(n);

cout<long int fac(int n) {

long int p; if(n= =0)

p=1; else

p=n*fac(n-1); return p; }

十、标识符的作用域(作用范围)

1、标识符的作用域的规则:标识符只能在说明它或定义它的范围是可见的,而在该范围之外是不可见的。 说明: 1)、可见是指可以进行存取或访问操作的,不可见是指不可以进行存取或访问操作的。 2)、大多数的标识符对它说明或定义是同一回事,只有少数的标识符对它说明和定义是两回事。例如:外部变量、函数和类等。 3)、标识符通常包括:常量名、变量名、类名、函数名、对象名、语句标号、数组名、指针名等等。 2、作用域的种类: 1)、程序级:a、组成:外部函数和外部变量

b、作用域:该程序的所有文件。

c、注意:此类标识符在操作之间一般都要先说明。

2)、文件级:a、组成:内部函数、外部静态变量和用宏定义的符号常量

b、作用域:定义它的文件内部。

3)、函数级:a、组成:函数参数、内部静态变量和在函数内定义的自动类变量。

b、作用域:定义它的函数内部。

c、注意:此类标识符不包括在函数里面的分程序、if、switch和循环语句内定义的变量。

4)、块级: a、组成:分程序、if、switch和循环语句内定义的自动类变量和内部静态变量。

b、作用域:相应结构内部。

3、关于重新定义标识符的作用域规定: 1)、在c++中,一般不允许在相同的作用域内定义同名的变量,但是在不同的作用域内可以定义同名的变量。 2)、重新定义标识符的作用域规定:在某个作用域范围内定义的标识符在该范围内的子范围内可以重新定义该标识符,这时原标识符在子范围内是不可见的,但是它还是存在的,只是被子范围内的同名标识符暂时隐藏起来,当子范围过去之后,原来的标识符又是可见的。 例1:#include void main( ) {

int a=5,b=7,c=10;

cout<int b=8; float c=8.8;

cout<< a<<‖,‖<int c; c=b;

cout<< a<<‖,‖<cout<< a<<‖,‖<cout<< a<<‖,‖<例2、#include void main( ) {

int x=3;

for (;x>0;x--) {

int x=5;

cout<cout<4、局部变量和全局变量 1)、局部变量:函数级和块级的变量。

A、组成:自动类变量、寄存器类变量、内部静态变量和函数的参数。

B、作用域:在所定义的函数体或分程序内部。

C、自动类变量:定义在函数体或分程序内的一种变量,定义时可加auto说明符,但其说明符也可省略。 D、寄存器类变量:定义在函数体或分程序内的一种变量,定义时前边加说明符rigester。

E、内部静态变量:定义在函数体或分程序内的一种变量,在定义时前边加static说明符,它的作用域与上述变量相同,但它的生存期更长(即在在定义它的作用域外,它虽然不可见,但是它仍然存在,它的值没有被释放,一旦它回到作用域后,仍然保留其原来的值。 例、#include void other( ); void main( ) {

int a=3;

register int b=5; static int c;

cout<<‖a=‖<void other( ) {

int a=5;

static int b=12; a+10; b+=20;

cout<<‖a=‖<2)、全局变量:程序级和文件级的变量。 A、组成:外部变量和外部静态变量。

B、作用域:外部变量的作用域在所定义的程序体内,外部静态变量的作用域在所定义的文件内。

C、外部变量:定义在函数体外的一种变量,定义时不要加任何说明符,但在另外一个文件要使用一个外部变量时必须先说明。

D、外部变量的说明方法:在变量的前边加说明符extern。

E、外部静态变量:定义在函数体外的一种变量,在定义时前边加static说明符。 文件1(main.cpp) #include void fun1( ),fun2( ),fun3( ); void main( ) {

I=20; Fun1( );

Cout<<‖main( ):I=‖<Cout<<‖main( ):I=‖<Cout<<‖main( ):I=‖<文件2(file1.cpp) #include static int I; void fun1( ) {

I=50;

Cout<<‖fun1( ):I(static)=‖<文件3(file2.cpp) #include void fun2( ) {

int I=15;

cout<<‖fun2:I(auto)=‖<extern int I;

cout<<‖fun2:I(extern)=‖<extern int I; void fun3( ) {

I=30;

cout<<‖fun3:I(extern)=‖<int I=10;

cout<<‖fun3:I(auto)=‖<5、内部函数和外部函数 1)、内部函数(静态函数):

a、内部函数是在定义它的文件中可以被调用的函数,而在同一程序中的其他文件中不能被调用。

b、定义格式:

Static 类型标识符 函数名 (参数表) {

函数体 }

c、 例:

#include int i=10;

static int reset(),next(int),last(int),other(int); void main() {

int i=reset();

for(int j=1;j<=3;j++) { cout<static int reset() {

return i; }

static int next(int j) {

j=i++; return j; }

static int last(int j) {

static int i=20; j=i--; return j; }

static int other(int i) {

int j=15;

return i=j+=i; }

2)、外部函数

a、外部函数是一种作用域在整个程序中的函数。 b、定义格式:

[exter n] 类型标识符 函数名 (参数表) {

函数体 } c、例

文件f1.cpp

#include int i=1;

extern int reset(),next(),last(),other(int); void main() {

int i=reset();

for(int j=1;j<=3;j++)

{ cout<文件f2.cpp extern int i;

extern int reset() {

return i; }

文件f3.cpp

static int i=10; extern int next( ) { return i+=1; }

extern int last( ) {

return i-=1; }

extern int other(int i) {

int j=5;

return i=j+=i; }

十一、c++的系统函数

1、系统函数的使用方法:先用预处理包含命令把定义函数的头文件(*.h)包含进来,然后在程序中通过函数直接调用。

2、c++系统将所提供的系统函数的定义或说明分类放在不同的头文件中。其中对应关系如下: 数学函数:math.h 字符函数:ctype.h 字符串函数: string.h 屏幕处理函数:conio.h 图形处理函数:graph.h

3、注意;在使用系统函数之前,一定要将该函数的功能、参数和返回值情况弄清楚。 4、例:

#include #include

const double pi=3.14159265; void main() {

double i=30*pi/180; double x=sin(i); double y=cos(i); double z=tan(i);

cout<<\"sin(30)=\"<第五章 类与对象

类是一种复杂的数据类型,它是将不同的类型的数据和与这些数据相关的操作封装在一起的集合体。C++

语言中提供了类这种工具使得应用中的实体在程序中可以直接被表示为一个标识符,并可以对它进行引用和操作,这就使得程序中的概念与应用中的概念相互比较一致和对应。 一、类的定义和对象的生成

在C++中,有三种类的类型:CLASS(类)、STRUCT(结构)、UNION(联合)。三种不同类的差别: 比较的方面 类 结构 联合 CLASS STRUCT UNION 定义的关键字 默认的访问权限 私有 公有 公有 使用限制 无 无 同时只能使用一个成员 1、定义CLASS的一般形式: CLASS 类名 {

PUBILC:

公有数据和成员函数的定义 PRIVATE:

私有数据和成员函数的定义 PROTECTED:

保护数据和成员函数的定义 }; 或者

CLASS 类名 {

PUBILC:

公有数据和成员函数的说明 PRIVATE:

私有数据和成员函数的说明 PROTECTED:

保护数据和成员函数的说明 };

<各个成员函数的实现>

其中class是关键字;类名是标识符,一般由字母T开头。

PROTECTED 、PUBILC、 PRIVATE是访问权限修饰符,一般PUBILC说明成员函数,PRIVATE说明成员函数,而且它们之间一般没有固定的顺序。 举例: class Tdate {

public:

void SetDate(int y , int m , int d); int IsLeapYear(); void Print(); private:

int year,month,day; };

void Tdate::SetDate(int y , int m , int d) {

year=y; month=m; day=d; }

int Tdate::IsLeapYear() {

return (year%4==0&&year%100!=0)||(year%400==0); }

void Tdate::Print() {

cout<定义一个关于圆的类,用于计算圆的面积和周长。 #include const double pi=3.14; class Circle {

public:

int radius;

double calculate_area() { return pi*radius*radius; }

double calculate_perimeter() { return 2*pi*radius; } };

void main() {

Circle theCircle;

cout<<\"请输入圆半径: \"; cin>>theCircle.radius;

cout<<\"圆面积为: \"<cout<<\"圆周长为: \"<3、定义类注意事项: 1)、在类体中不允许对它所定义的数据成员进行初始化 2)、类中的数据成员的类型可以任意的 3)、一般,在类体内先说明公有成员,并且一般按数据成员的类型大小,由小到大说明 4)、经常将类定义的说明部分或整个定义部分放到一个头文件中。 二、对象的定义

1、对象的定义格式: 类名 对象名表

其中:对象名可以是一般的对象名,还可以是指向对象的指针名或引用名。例如;

Tdate date1 , date2 , *pdate , data[31] , &Tdate=date3; 2、对象成员的表示方法: (一)一般对象 对象名.成员名

对象名.成员名(<参数表>) (二)指针对象

对象名->成员名 或 (*<对象指针名>)->成员名

对象名->成员名(<参数表>)或(*<对象指针名>)->成员名 (三)引用对象的成员表示与一般对象的成员表示相同。 #include class Tdate {

public:

void SetDate(int y , int m , int d);

int IsLeapYear(); void Print(); private:

int year,month,day; };

void Tdate::SetDate(int y , int m , int d) {

year=y; month=m; day=d; }

int Tdate::IsLeapYear() {

return (year%4==0&&year%100!=0)||(year%400==0); }

void Tdate::Print() {

cout<void main() {

Tdate date1,date2;

date1.SetDate(1996,5,4); date2.SetDate(1998,4,9); int leap=date1.IsLeapYear(); cout<三、对象的初始化和释放 (一)构造函数:

如果类中某个成员函数的名称与类名称相同,那么这个函数是构造函数。构造函数不能有返回值。当一个对象被建立时,程序就会自动调用这个类的构造函数为这个对象进行初始化。 例如:定义构造函数: // OutClass.h 定义类 class OutClass { private: int i; public: OutClass ( ); OutClass( int n); };

// OutClass.cpp 成员函数的实现 #include #include \"OutClass.h\" OutClass :: OutClass( ) {

i=0;

cout << \"默认初始化i =\"<< i << endl; }

OutClass :: OutClass(int n) {

i= n;

cout << \"初始化i=\" << \" \" << i << endl; }

//以下是程序调用 void main( ) {

OutClass theOutClass1;

OutClass theOutClass1( 10000); }

构造函数的特点: 1)、构造函数是成员函数,函数体可写在类体内,也可写在类体外。 2)、构造函数是一个特殊的函数。该函数可以有1个参数,也可以有多个参数,并且该函数不指定类型说明 3)、构造函数可以重载。 (二)析构函数

1、析构函数是“反向“的构造函数,它们在对象被撤消是自动调用,析构函数的名称除了最前面的”~“符号外,与类的名称相同。例如类string的析构函数是~string( ).在一个类中只可能定义一个析构函数。 2、对象的释放发生在以下几种情况:

使用运算符new分配的对象被delete删除

一个具有块作用域的本地对象超出其作用域(例如函数)。 临时对象的生存周期结束 程序运行结束

使用完全限定名显示调用对象的析构函数 3、析构函数的规则: 不能接受参量

不能说明有任何返回类型 不能用return 语句返回值 不能说明为const static 例如:

#include class Tdate {

public:

~Tdate();

Tdate(int y,int m,int d); void Print(); private:

int year,month,day; };

Tdate::Tdate(int y , int m , int d) {

year=y; month=m; day=d;

cout<<\"constructor caaled.\\n\"; }

Tdate::~Tdate() {

cout<<\"destructor called.\\n\"; }

void Tdate::Print() {

cout<void main() {

Tdate today(1998,4,9),tomorrow(1998,4,10); cout<<\"today is\"; today.Print(); cout<<\"today is\"; tomorrow.Print(); }

(三)缺省构造函数和缺省析构函数

在类定义时没有定义任何构造函数或者析构函数时,则编译器自动生成一个不带参数的缺省构造函数或者缺省析构函数。

缺省构造函数格式如下:

<类名>::<缺省构造函数名>( ) { }

在用缺省构造函数对对象初始化时,则将对象的所有数据成员都初始化为零或空。

缺省析构函数格式如下:

<类名>::<缺省析构函数名>( ) { }

(四)拷贝初始化构造函数

拷贝初始化构造函数是一种特殊的成员函数,它的功能是用一个已知的对象来初始化一个被创建的同类的对象。

拷贝初始化构造函数的特点如下:

1、该函数名同类名,因为它也是一种构造函数,并且该函数也不被指定返回类型。 2、该函数只有一个参数,并且是对某个对象的引用。

3、每个类都必须有一个拷贝初始化构造函数,其格式如下所示: <类名>::<拷贝初始化构造函数>(const<类名>&<引用名>)

4、如果类中没有说明拷贝初始化构造函数,则编译系统自动生成一个具有上述形式的缺省拷贝初始化构造函数,作为该类的公有成员。 例如:

#include class Tpoint {

public:

Tpoint(int x,int y){X=x;Y=y;} Tpoint(Tpoint &p);

~Tpoint(){cout<<\"destructor Called.\\n\";} int Xcoord(){return X;} int Ycoord(){return Y;} private: int X,Y; };

Tpoint::Tpoint(Tpoint&p) {

X=p.X; Y=p.Y;

cout<<\"copy_initalization constructor called.\\n\"; }

void main() {

Tpoint p1(5,7); Tpoint p2(p1);

cout<<\"p2=\"<三、成员函数的特性

1、内联函数和外联函数: 1)、内联成员函数: a、定义方式有两种:一种是把函数体的实现写在类体里面,另一种是把外联成员函数转变成内联函数(在外联函数前加关键字inline)。

b、注意内联函数与外联函数的区别(与普通的函数相同)。 c、例: class A {

public:

A(int x,int y) {X=x;Y=y;} int a() {return X;} int b() {return Y;} int c(); int d(); private: int X,Y; };

inline int A::c() {

return a()+b(); }

inline int A::d() {

return c(); }

#include void main() {

A m(3,5); int i=m.d();

cout<<\"d() return:\"<2、重载性:成员函数和普通函数一样也可以重载。(其含义和定义、调用方法与普通函数相同)。 例:class M {

public:

M(int x,int y) {X=x;Y=y;} M(int x) {X=x;Y=x*x;} int Add(int x,int y); int Add(int x); int Add( );

int Ycout() {return Y;} int Xcout() {return X;} private: int X,Y; };

int M::Add(int x,int y) {

X=x; Y=y;

return X+Y; }

int M::Add(int x) {

X=Y=x; return X+Y; }

int M::Add( ) {

return X+Y; }

#include void main() {

M a(10,20),b(4);

cout<<\"a=\"<cout<3、设置成员函数参数的缺省值:成员函数和普通函数一样也可以设置缺省值。(其含义和定义方法与普通函数相同)。 例:class N {

public:

N(int a=3,int =5,int c=7); int Aout() {return A;} int Bout() {return B;} int Cout() {return C;} private:

int A,B,C; };

N::N(int a,int b,int c) {

A=a; B=b; C=c; }

#include void main() {

N X,Y(9,11),Z(13,15,17);

cout<<\"X=\"<四、静态成员

1、静态成员包括静态成员数据和静态成员函数,提出静态成员主要是为力实现数据共享。 2、一个通过设置全局变量来实现数据共享的例子: #include int g=5;

void f1(),f2(); void main() {

g=10; f1(); f2();

cout<void f1() {

g=15; }

void f2() {

g=20; }

3、静态数据成员:它是类的所有对象中公有(共享)的成员,而不是某个对象的成员。对多个对象来说,静态数据成员只存储一处,供所有对象公用,静态数据成员的值对每个对象都是一样的,但它的值是可以更新的。只要对静态数据成员的值更新一次,保证所有对象存取更新后相同的值。从而实现数据的共享。 1)、定义方法:加关键字static 2)、初始化方法:只能在类外部来实现。格式: <数据类型><类名>::<静态数据成员名>=<初试值>; 3)、静态数据成员是静态存取的,它是静态生存期。 4)、例:#include class Myclass {

public:

Myclass(int a,int b,int c); void GetNumber(); void GetSum(); private:

int A,B,C; static int Sum; };

int Myclass::Sum=0;

Myclass::Myclass(int a,int b,int c) {

A=a; B=b; C=c;

Sum+=A+B+C; }

void Myclass::GetNumber() {

cout<<\"number=\"<void Myclass::GetSum() {

cout<<\"sum=\"<void main() {

Myclass M(3,7,10),N(14,9,11); M.GetNumber(); N.GetNumber(); M.GetSum(); N.GetSum(); }

4、静态成员函数:它与静态数据成员基本相同。 1)、例:#include class Myclass {

public:

Myclass(int a) {A=a;B+=a;} static void f1(Myclass m); private: int A;

static int B; };

int Myclass::B=0;

void Myclass::f1(Myclass m) {

cout<<\"A=\"<void main() {

Myclass P(5),Q(10); Myclass::f1(P); Myclass::f1(Q); } 2)、在main函数中,调用静态成员函数的格式:

<类名>::<静态成员函数名>(<参数表>) 3)、注意:在静态成员函数中不能直接引用类中的非静态成员,可以引用类中说明的静态成员。如果静态成员函数中引用非静态成员时,必须通过对象来引用。 五、友元

1、友元是一种定义在类外部的普通函数,但是需要在类体里面进行说明的函数。并且在说明时需要在函数名前加关键字friend。它虽然不是类的成员函数,但是它可以访问类的私有成员。 2、友元可以分为友元函数和友元类两种。

3、友元函数:从语法上看,它在定义和调用上与普通成员函数一样,但是它不需要进行类型检查和安全性检查等,因此可以减少运行时间的开销,提高运行效率。 例1:

#include #include class Point {

public:

Point(double xx,double yy) {x=xx;y=yy;} void Getxy();

friend double Distance(Point&a,Point&b); private:

double x,y; };

void Point::Getxy() {

cout<<\"(\"<double Distance(Point&a,Point&b) {

double dx=a.x-b.x; double dy=a.y-b.y;

return sqrt(dx*dx+dy*dy); }

void main() {

Point p1(3.0,4.0),p2(6.0,8.0); p1.Getxy(); p2.Getxy();

double d=Distance(p1,p2);

cout<<\"Distance is\"<例2:#include class Time {

public:

Time(int xhours,int xminutes)

{ hours=xhours; minutes=xminutes; }

friend void time12(Time time); friend void time24(Time time); private:

int hours,minutes; };

void time12(Time time) {

if(time.hours>12) { time.hours-=12; cout<void time24(Time time) {

cout<void main() {

Time time1(20,30),time2(10,45); time12(time1); time24(time1); time12(time2); time24(time2); }

4、友元类:可以定义一个类作为另一个类的友元类。此时友元类里面的所有成员函数都是主类的友元函数。例如类Y是类X的友元类,那么类Y中的所有成员函数都是类X的友元函数(注意:此时类Y必须在类X中先说明)。例:

#include class X {

friend class Y; public:

void Set(int i) { x=i; }

void Display() { cout<<\"x=\"<static int y; };

class Y {

public:

Y(int i,int j); void Display(); private: X a;

};

int X::y=1; Y::Y(int i,int j) {

a.x=i; X::y=j; }

void Y::Display() {

cout<<\"x=\"<void main() {

X b; b.Set(5); b.Display(); Y c(6,9); c.Display(); b.Display(); }

六:类的作用域

1、类的作用域:简称为类域,它是指类的定义范围。类的成员的作用域就是该类的类域。 2、文件域可以包含类域。 3、例:#include class A {

public:

A(int x,int y) { X=x; Y=y; }

int Xcoord() {return X;} int Ycoord() {return Y;} void Move(int dx,int dy); private: int X,Y; };

int X=9,Y=18;

void A::Move(int dx,int dy) {

X+=dx; Y+=dy;

cout<void main() {

A a(4,5); a.Move(1,2); }

4、某个类A中某个成员M在下列情况下具有类A的作用域: 1)、该成员M出现在该类的某个成员函数中,并且该成员函数没有定义同名标识符。 2)、在该类A的某个对象的该成员M的表达式中。 3)、在该类A的某个指向对象指针的该成员M的表达式中。 4)、在使用作用域运算符所限定的表示式中。

七、局部类和嵌套类(实际应用很少用,简单了解) 1、局部类:

1)、在一个函数体内定义的类称为局部类。 2)、例:int a; void main() {

static int s; class A {

public: void int(int i) {s=i;} }; A m;

m.init(10); } 3)、注意:局部类中不能定义静态成员函数,并且所有成员函数都必须定义在类体内。 2、嵌套类: 1)、在一个类中定义的类称为嵌套类。定义嵌套类的类称为外围类。 2)、例: class A {

public: class B {

public: ......... private: ......... };

void f(); private: int a; }; 3)、a、嵌套类中的成员函数不能在它的类体外定义。

B、嵌套类只是格式上的嵌套。在分析嵌套类时,可以嵌套类看成非嵌套类。 C、例:

class A {

public: void f(); private: int a; };

…………. class B {

public: ......... private: ......... };

八、对象的生存期

1、所谓对象的生存期是指对象从被创建开始到被释放为止的时间。

2、按生存期的不同对象可以分为三种:局部对象、静态对象、全局对象。

3、局部对象:被定义在一个函数体或程序块内。它的生存期是从对象创建到程序退出定义该对象所在的函数体或程序块为止。

4、静态对象:被定义在一个文件的函数中。它的生存期是从对象创建到文件结束。

5、全局对象:被定义在一个文件中。它的生存期是从程序开始到程序结束。

6、注意:对象的生存期的开始时刻调用构造函数,在生存期结束的时刻调用析构函数。 7、例:#include #include class A {

public:

A(char*st); ~A(); private:

char string[50]; };

A::A(char*st) {

strcpy(string,st);

cout<<\"call for\"<A::~A() {

cout<<\"destryctor called for\"<void fun() {

A funobject(\"funobject\");

static A staticobject(\"staticobject\"); cout<<\"in fun\"<A globalobject(\"globalobject\"); void main() {

A mainobject(\"mainobject\");

cout<<\"in main,befor called for\"<cout<<\"in main,after called for\"<第六章 类和对象(二)

一、对象指针和对象引用

1、在c++中,可以说明指向对象的指针,也可以定义指向类的成员的指针。 2、指向类的成员的指针: 1)、定义格式:

<类型说明符><类名>::*<指针名> <类型说明符>(<类名>::*<指针名>)(<参数表>) 例: class A {

public:

int fun (int b) {return a*c+b;} A (int I) {a=I;} Int c; Private:

Int a; };

…………………………….. int A::*pc=&A::c; int (A::*pfun)(int)=A::fun;

2)、使用方法:在使用指针时,需要首先指定A类的一个对象,然后,通过对象(包括一般对象和指针对象)来引用指针所指向的成员。例如: A a; a.*pc=8;

A * p=&a; p->*pc=8; 3)、例:

#include class A {

public:

A(int i) {a=i;}

int fun(int b) {return a*c+b;} int c; private: int a; };

void main() {

A x(8); int A::*pc; pc=&A::c; x.*pc=3;

int(A::*pfun)(int); pfun=A::fun; A*p=&x;

cout<<(p->*pfun)(5)<3、对象作函数参数的使用 1)、一般对象作函数的参数 2)、对象指针作函数参数(与普通函数的情况相同)例: #include class M {

public:

M() {X=Y=0;}

M(int i,int j) {X=i;Y=j;} void copye(M *m);

void setxy(int i,int j) {X=i;Y=j;}

void print() {cout<void M::copye(M *m) {

X=m->X; Y=m->Y; }

void fun(M m1,M *m2); void main() {

M p(5,7),q; q.copye(&p); fun(p,&q); p.print(); q.print(); }

void fun(M m1,M *m2) {

m1.setxy(12,15); //m1.print();

m2->setxy(22,25); } 3)、对象引用作函数的参数(与普通函数的情况相同)例: #include class M {

public:

M() {X=Y=0;}

M(int i,int j) {X=i;Y=j;} void copye(M &m);

void setxy(int i,int j) {X=i;Y=j;}

void print() {cout<void M::copye(M &m) {

X=m.X; Y=m.Y; }

void fun(M m1,M &m2); void main() {

M p(5,7),q; q.copye(p); fun(p,q); p.print(); q.print(); }

void fun(M m1,M &m2) {

m1.setxy(12,15); m2.setxy(22,25); }

二、数组: 1、对象数组: 1)、对象数组是指数组元素为对象的数组。 2)、定义格式

<类名><数组名>[<大小>]……. 3)、对象数组的赋值

对象数组可以被赋初值,也可以被赋值。 4)、例:

2、指向数组的指针和指针数组 1)、指向数组的指针:表示定义一个指针它指向数组(一般数组和对象数组)。 2)、定义格式:

<类型说明符>(*<指针名>)[<大小>]…….. 例:int (*p) [4]; int (*p)[4][6]; M (*p)[7] 3)、例1:

#include

int a[][3]={1,2,3,4,5,6,7,8,9}; void main()

{

int (*p)[3](a);

for(int i=0;i<3;i++) { cout<cout<例2:

#include class M {

public:

M() {a=b=0;}

M(int i, int j) {a=i;b=j;}

void print(){cout<void main() {

M m[2][4]; int x=10,y=10; for(int i=0;i<2;i++) for(int j=0;j<4;j++) m[i][j]=M(x+=2,y+=10); M(*pm)[4](m); for(i=0;i<2;i++) { cout<<类型名>*<数组名>[<大小>]………..

例如:int *pa[3] int *pc[2][5] char *p[5] M *p[4]

注意:在c++编程中,经常使用char型的指针数组来存放若干个字符串。 例1:编程实现从键盘上接收若干个字符串,并且将他们显示在屏幕上。 #include #include const int n=5; void main() {

char*strings[n]; char str[80];

cout<<\"at each prompt ,enter a string\\n\"; for(int i=0;icout<例2:

#include class A {

public:

A(int i=0,int j=0){a=i;b=j;} void print(); private: int a,b; };

void A::print() {

cout<void main() {

A a1(7,8),a2,a3(5,7); A*b[3]={&a3,&a2,&a1}; for(int i=0;i<3;i++) b[i]->print(); }

三、常类型

1、常类型是用类型修饰符const说明的类型。常类型的值定义好了以后,在整个文件中其值不能更新。因此在说明或定义常类型时必须初始化。 2、一般常量和对象常量 1)、一般常量

格式:

<类型说明符> const <标示符名> = 数值; const <类型说明符> <标示符名> = 数值; 2)、对象常量

格式:

<类名> const <对象名>; const <类名> <对象名>; 例: class A {

public:

A(int i,int j){x=i;b=j;} .......... private: int x,y; };

..............

const A a1(7,8); A const a2,a3(5,7); 3、常指针和常引用 1)、常指针:在使用const修饰常指针时,要注意const的位置。

例如:char * const ptr1=stringptr1; 这是定义一个指向字符串的指针常量。 const char * ptr1=stringptr1; 这是定义一个指向字符串常量的指针。 2)、常引用:在c++中可以使用const来说明引用,被说明的引用为常引用,该引用所引用的对象不能更新。其定义格式如下:

const <类型说明符> & <引用名>

3)、在c++的实际编程应用中,常指针和常引用经常用来作函数的形式参数,这样的参数称为常参数。 例1:#include const int n=6;

void print(const int *p,int n); void main() {

int array[n];

for(int i=0;i>array[i]; print(array,n); }

void print(const int *p,int n) {

cout<<\"{\"<<*p; for(int i=1;i例2:#include class K {

public:

K(int i) {k=i;}

int setk() const {return k;} private: int k; };

int add(const K&g1,const K&g2); void main() {

K k1(8),k2(17); int s=add(k1,k2); cout<int add(const K&g1,const K&g2) {

int sum=g1.setk()+g2.setk(); return sum; }

4、常成员函数

只有常成员函数才能操作常量或常对象。常成员函数说明的格式如下: <类型说明符><函数名>(<参数表>)const;

注意:1、const是加在函数说明后面的类型修饰符,她是函数类型的一个组成部分,在函数的实现部分也要加const关键字。

2、常成员函数和同名的非常成员函数构成重载。 例:#include class r {

public:

r(int i,int j) {r1=i;r2=j;} void print();

void print() const; private:

int r1,r2; };

void r::print() {

cout<}

void r::print() const {

cout<void main() {

r a(5,4); a.print();

const r b(20,50); b.print(); }

5、常成员数据

注意:常成员数据的初始化只能成员初始化列表的方式来生成构造函数对成员数据初始化。 例:#include class r {

public: r(int i);

void print(); const int& a; private: int c;

static const int d; };

const int r::d=10; r::r(int i):c(i),a(c) { }

void r::print() {

cout<void main() {

r k1(100),k2(0); k1.print(); k2.print(); }

四、子对象和堆对象 (一)子对象

1、当一个类的成员是某个类的对象时,该对象就是子对象。因此子对象就是对象成员。 例:class a {

public: ......... private: ......... }; class b {

public: ........ private: a k; int p;

};

2、子对象的初始化:

在一个类中出现子对象或者对象成员时,该类的构造函数要包含对子对象的初始化,通常采用成员初始化列表的方法来初始化子对象。 例:#include class r {

public:

r(int i,int j) {r1=i;r2=j;} void print(); private:

int r1,r2; };

void r::print() {

cout<class b {

public:

b(int i,int j,int k):a(i,j),n(k) { }

void print(); private: r a; int n; };

void b::print() {

a.print();

cout<void main() {

b x(6,7,8); x.print(); }

(二)堆对象

1、所谓堆对象是指在程序运行过程中根据需要可以建立或删除的对象。 2、创建或删除堆对象时,需要如下两个运算符: new :创建 delete :删除 3、new的用法: (1)、创建堆对象(动态地创建对象)

格式:new <类型说明符>(<初始值列表>) 注意:

a、new运算符返回一个指针

b、如果new运算符不能分配到所需要的内存,它返回0;也就是空指针。 例: A *ptr;

Ptr =new A(5,6)

(2)动态的创建数组

格式:new <类型说明符> [<数组大小>] 例:

int *p;

p=new int[10];

A *p;

p=new A[9]; 4、delete的用法

delete运算符的功能是用来删除使用new创建的对象或一般类型的指针。 格式:

delete <指针名>; delete[ ] <指针名>;

注意:a、如果是删除对象,程序将自动调用析构函数

b、如果是删除数组,则不管数组的大小、维数都使用以上格式。 例: A *ptr;

Ptr =new A(5,6) Delete ptr;

int *p;

p=new int[10]; delete p;

A *p;

p=new A[9]; delete[] p; 例1、

#include class AA {

public:

AA(int i,int j) { A=i;B=j; cout<<\"constructor.\\n\"; }

~AA() {

cout<<\"destructor.\\n\"; }

void print(); private:

int A,B; };

void AA::print() {

cout<void main() {

AA *a1,*a2; a1=new AA(1,2); a2=new AA(5,6); a1->print(); a2->print(); delete a1; delete a2; }

例2:#include #include

class AA {

public:

AA(char *s,double n) { strcpy(name,s); b=n;

cout<<\"constructor.\\n\"; }

AA() {cout<<\"default constructor.\\n\";} ~AA() {

cout<<\"destructor.\"<void getb(char *s,double&n) { strcpy(s,name); n=b; } private:

char name[80]; double b; };

void main() {

AA *P; double n; char s[80]; P=new AA[3];

P[0]=AA(\"ma\ P[1]=AA(\"wang\ P[2]=AA(\"li\ for (int i=0;i<3;i++) { P[i].getb(s,n); cout<delete[] P; }

#include #include class AA {

public:

AA(int a,int b) { width=a; longth=b; }

AA() {} int area() { return width*longth; }

int addarea(AA a1,AA a2) { return a1.area()+a2.area(); }

private:

int width,longth; };

void main() {

int a,b;

cout<<\"请输入第一个长方形的宽(a)和长(b)\"<>a>>b; AA X1(a,b);

cout<<\"第一个长方形的面积为\"<cout<<\"请输入第二个长方形的宽(a)和长(b)\"<>a>>b; AA X2(a,b);

cout<<\"第二个长方形的面积为\"<cout<<\"两个长方形的面积之和为\"<第七章 类的继承

类的继承就是创建一个具有别的类的属性和行为的新类。即从已有的对象类型出发,建立一种新的对象类型,使它具有原对象的特点和功能。

继承是一种类的层次模型,并有允许和鼓励类的重用。她提供一种明确表示共性的方法。对象的一个新类可以从现有的类中派生,这个过程称为类的继承。

新类继承了原始类的特性,新类称为原始类的派生类(子类),而原始类称为新类的基类(父类)。 派生类可以从它的基类继承方法和实例变量,并且可以修改或增加新的方法使之更适合特殊的需要。 C++中有两种继承:单一继承和多重继承。单一继承是指派生类的基类只有一个。而多重继承的派生类有多个基类。

一、单一继承:

1、定义单一继承的一般格式:

cl a s s 派生类名:继承方式(private\\public\\protected) 基类名 {

private:

派生类新定义的成员 public:

派生类新定义的成员 protected:

派生类新定义的成员 }; 例:

#include class A {

public: int a() { return 0; } };

class B {

public:

float b() { return (4.14); }

};

class C : public A, public B { };

void main() {

C theC;

cout<2.单一继承的特点:

a.类的派生是没有限制的,但构造函数和析构函数不能继承。 b.缺省的继承方式是私有方式。

C.在继承中,派生类含有基类的成员加上任何新增的成员。

3、派生时满足赋值兼容原则,也就是在公有派生的情况下,基类成员在派生类中的访问权限不变,在私有派生的情况下,基类成员在派生类中的访问权限均为私有类型。 4.不同派生方式得到的派生类对基类成员的访问权限: 继承方式 基类的特性 派生类的特性 Public Public Protected Protected 公有继承 Private 不可访问 Public Private Protected Private 私有继承 Private 不可访问 Public Protected Protected Protected 保护继承 Private 不可访问 5、在公有继承方式下: 1)、基类成员对其对象的可见性:

公有成员可见,其他不可见 2)、基类成员对派生类的可见性:

公有成员和保护成员可见,其他不可见 3)、基类成员对派生类对象的可见性:

公有成员可见,其他不可见。 4)、总之:在公有继承时,派生类的成员函数可访问基类中的公有成员和保护成员;派生类的对象只能访问基类中的公有成员。例: #include class A {

public:

void f1(); protected: int j1; private: int i1; };

class B:public A {

public:

void f2(); protected: int j2; private: int i2; };

class C:public A {

public:

void f3(); };

问题: 1)、派生类B中成员函数f2()能否访问基类A中的成员:f1(),i1,j1? 2)、派生类B的对象b1能否访问基类A中的成员:f1(),i1,j1? 3)、派生类C中成员函数f3()能否访问基类B中的成员:f2(),i2,j2?能否访问基类A中的成员:f1(),i1,j1? 4)、派生类C的对象c1能否访问基类B中的成员:f2(),i2,j2?能否访问基类A中的成员:f1(),i1,j1?

6、在私有继承方式下: 1)、基类成员对其对象的可见性:

公有成员可见,其他不可见 2)、基类成员对派生类的可见性:

公有成员和保护成员可见,其他不可见 3)、基类成员对派生类对象的可见性:

所有成员都不可见。 例:

#include class A {

public:

void f(int i) {cout<class B:public A {

public:

void h() {cout<<\"h\"<void main() {

B d; d.f(6); d.g(); d.h(); }

问题: 1)、执行程序时,哪个语句会出现编译错误?为什么? 2)、去掉错误语句后,程序的运行结果如何? 3)、派生类B中,A::f的含义是什么? 4)、将派生类B的继承方式改为公有继承程序的结果又怎样? 三、在类的派生过程中,构造函数和析构函数的使用 1、构造函数: 1)、基类子对象:派生类的对象中由基类中说明的数据成员和操作所构成的封装体;它是由基类中的构造函数进行初始化。 2)、构造函数不能被继承。因此,派生类的构造函数必须通过调用基类的构造函数来初始化基类子对象。所以在定义派生类的构造函数时除了对自己的数据成员进行初始化外,还必须负责调用基类构造函数使基类的数据成员得以初始化。并且如果派生类中还有子对象时,还应该包含对子对象初始化的构造函数。 3)、派生类构造函数的定义格式: <派生类名>(<总参数表>):<基类构造函数>(<参数表>),<子对象名>(<参数表>) {

派生类中数据成员初始化; } 4)、派生类构造函数的调用顺序: 基类的构造函数 子对象的构造函数 派生类的构造函数 例:#include class A {

public:

A() {a=0;cout<<\"A's default constructor called.\"<class B:public A {

public:

B() {b=0;cout<<\"B's default constructor called.\"<~B() {cout<<\"B's destructor called.\"<B::B(int i,int j,int k):A(i),aa(j) {

b=k;

cout<<\"B's constructor called.\"<void B::print() {

A::print();

cout<void main() {

B bb[2];

bb[0]=B(1,2,5); bb[1]=B(3,4,7); for(int i=0;i<2;i++) bb[i].print(); }

5)、派生类构造函数使用中应注意的问题:

派生类构造函数的定义中可以省略对基类构造函数的调用,其条件是在基类中必须有缺省的构造函数或者根本没有定义构造函数。

当基类的构造函数使用一个或多个参数时,则派生类必须定义构造函数,提供将参数传递给基类构造函数途径。

2、析构函数:

由于析构函数不能被继承,因此在执行派生类的析构函数时,基类的析构函数也将被调用。执行顺序是先执行派生类的析构函数,再执行基类的析构函数。例: #include

class A {

public:

A() {m1=m2=0;}

A(int i,int j) {m1=i;m2=j;}

~A() {cout<<\"A's destructor called.\"<void print() const {cout<int m1,m2; };

class B:public A {

public:

B() {n=0;}

B(int i,int j,int k);

~B() {cout<<\"B's destructor called.\"<B::B(int i,int j,int k):A(i,j),n(k) { }

void main() {

B n1(5,6,7),n2(-2,-3,-4); n1.print(); n2.print(); }

3.举例:

class documents {

public:

char * title;

void outputtitle( ); }

viod documents::outputtitle( ) {

cout<class book:public documents {

public:

book(char * title,long pagecount); private:

long pagecount; };

book::book(char * title,long pagecount) {

strcpy (Title,title);

pagecount=pagecount; }

二、多重继承

1、多重继承是指一个派生类由多个基类派生而来,它是单一继承的自然扩展。 2、定义多重继承的一般形式:

class 子类名:访问控制 基类名1 , 访问控制 基类名2,…访问控制 基类名n

{

……//定义派生类自己的成员 };

1、 多继承的构造函数 1)、格式

<派生类名>(<总参数表>):<基类构造函数1>(<参数表>),<基类构造函数2>(<参数表>)<子对象名>(<参数表>) {

派生类中数据成员初始化; } 2)、a、派生类的构造函数的参数个数必须包含完成所有基类初始化所需的参数的个数。

B、执行顺序:先执行所有基类的构造函数,再执行子对象的初始化函数,最后执行派生类自己的构造

函数。并且处于同一层次的各基类构造函数的执行顺序取决于定义派生类时所指定的各基类顺序,与派生类构造函数中所定义的成员初始化列表的顺序无关。

#include class B1 {

public:

B1(int i) { b1=i; cout<<\"constructor B1.\"<void print() {cout<class B2 {

public:

B2(int i) { b2=i; cout<<\"constructor B2.\"<void print() {cout<class B3 {

public:

B3(int i) { b3=i; cout<<\"constructor B3.\"<int getb3() {return b3;} private: int b3; };

class A:public B2, public B1 {

public:

A(int i,int j,int k,int l):B1(i),B2(j),f(k) { a=l;

cout<<\"constructor A.\"<void print() { B1::print(); B2::print(); cout<private: int a; B3 f; };

void main() {

A aa(1,2,3,4); aa.print(); }

2、 二义性问题:

一般说来,在派生类中对基类成员的访问应该是唯一的。但是,由于多继承情况下,可能造成对基类中某个成员的访问出现不唯一的情况,则称为对基类成员访问的二义性问题。 主要表现为两个方面:

(一)在一般的多继承情况下: #include class A {

public: int a() { return 0; } };

class B {

public: float a() { return 4.0; } };

class C : public A, public B { };

void main() {

C theC;

cout<解决方法: 1)、通过成员名限定法来消除二义性 2)、在子类中定义一个同名成员,再在子类中根据需要来决定调用哪个基类的同名成员。 (二)、当一个派生来从多个基类派生,而这些基类又有一个共同的基类,则对该基类中说明的成员进行访问时,可能会出现二义性。例: #include class A {

private: int a; };

class B1:public A {

private: int b1; };

class B2:public A {

private: int b2; };

class C : public B2, public B2 {

public:

int f(); private: int c; };

................ C c1; c1.a; c1.A::a; c1.B1::a; 解决方法: 1)、通过成员名限定法来消除二义性 2)、把基类定义成需基类。 例

#include class A {

public:

A(int i) {a=i,cout<<\"con.A\"<class B1: public A {

public:

B1(int i,int j):A(i) {b1=j,cout<<\"con.B1\"<void print() {A::print(),cout<class B2: public A {

public:

B2(int i,int j):A(i) {b2=j,cout<<\"con.B2\"<void print() {A::print(),cout<class C: public B1,public B2 {

public:

C(int i,int j,int k,int l,int m):B1(i,j),B2(k,l),c(m)

{ cout<<\"con.C\"<void print() { B1::print(); B1::print(); cout<~C() {cout<<\"des.C\"<void main() {

C c1(1,2,3,4,5); c1.print(); }

三、虚基类

1、虚基类引入的原因:

2、定义格式: virtual <继承方式> <基类名>

把一个类定义成虚基类以后,那么他的直接或间接子类中的基类子对象都会合成一个子对象。 例1:#include class A {

private: int a; };

class B1:virtaul public A {

private: int b1; };

class B2: virtaul public A {

private: int b2; };

class C : public B2, public B2 {

public:

int f(); {

return a; private: int c; };

................ C c1; c1.a; 例22

3、虚函数的构造函数。 1)、虚基类子对象只有一个,因此虚基类构造函数也只要调用一次。 2)、最派生类:建立对象时指定的类称为最派生类。C++规定,虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化。 3)、如果一个派生类有一个直接或间接的虚基类,那么派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用,如果没有列出,则表示使用该虚基类的缺省构造函数来初始化派生类对象中的虚基类子

对象。 4)、虚基类子对象是由最派生类的构造函数通过调用虚基类的构造函数进行初始化。而该派生类的基类中所列出的对这个虚基类的构造函数的调用被忽略。 5)、执行顺序:先执行虚基类的构造函数 ,在执行非虚基类的构造函数。例 #include class A {

public:

A(const char *s) {cout<class B:virtual public A {

public:

B(const char *s1,const char *s2):A(s1) { cout<class C:virtual public A {

public:

C(const char *s1,const char *s2):A(s1) { cout<class D : public B, public C {

public:

D(const char *s1,const char *s2,const char *s3,const char *s4):B(s1,s2),C(s1,s3),A(s1) { cout<void main() {

D *ptr=new D(\"class a\ delete ptr; }

多态性和虚函数

多态性是指允许不同的类的对象对同一消息(对函数的调用)作出不同的响应。或者是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。类的多态性包括两个方面: a、函数重载和运算符重载 b、通过虚函数实现的多态性 一、 函数重载:例: #include #include class string {

public:

string(char *s); string(string &s1); string(int size=80); ~string() {delete sptr;}

int getlen() {return length;}

void print() {cout<int length; char *sptr; };

string::string(char *s) {

length=strlen(s);

sptr=new char[length+1]; strcpy(sptr,s); }

string::string(string &s1) {

length=s1.length;

sptr=new char[length+1]; strcpy(sptr,s1.sptr); }

string::string(int size) {

length=size;

sptr=new char[length+1]; *sptr='\\0'; }

void main() {

string str1(\"this is a string.\"); str1.print();

cout<cout<函数重载注意事项: 1)、不要使用毫不相干的函数来重载。 2)、在重载函数中使用缺省参数时,要注意二义性问题。例:void print(int a,int b) {

cout<void print(int a,int b,int c=50) {

cout<..........

print(50,12);

二、 运算符重载 (一)、

1、运算符重载实际是函数重载,因此编译程序对运算符重载的选择,遵循函数重载的选择原则。 2、几乎所有的运算符都能重载。但是不能重载的运算符有:. .* :: ?: 3、运算重载的函数一般采用的形式:成员函数形式和友元函数形式 4、注意事项: 1)、不能臆造新的运算符 2)、不能改变运算符操作数的个数。 3)、不能改变运算符原有的优先级、结合性和语法结构。 (二)、重载为类的成员函数

1、格式:

<类名> operator <运算符> (<参数表>)

2、重载为成员函数时,总是隐含了一个this指针参数,所以双目运算符仅有一个参数,单目运算符,重载为成员函数时,不能再显式说明参数。例: #include #include class string {

public:

string( ) {real=imag=0;} string(double r,double i) { real=r;imag=i; }

string operator +(const string &c); string operator -(const string &c); string operator *(const string &c); string operator /(const string &c); friend void print(const string &c); private:

double real,imag; };

inline string string::operator +(const string &c) {

return string(real+c.real,imag+c.imag); }

inline string string::operator -(const string &c) {

return string(real-c.real,imag-c.imag); }

inline string string::operator *(const string &c) {

return string(real*c.real-imag*c.imag, real*c.imag+imag*c.real); }

inline string string::operator /(const string &c) {

return string((real*c.real+imag*c.imag)/(c.real*c.real+c.imag*c.imag), (c.real*imag-c.imag*real)/(c.real*c.real+c.imag*c.imag)); }

void print(const string &c) {

if(c.imag<0) cout<void main() {

string c1(2.0,3.0),c2(4.0,-2.0),c3; c3=c1+c2;

cout<<\"\\nc1+c2=\"; print(c3); c3=c1-c2;

cout<<\"\\nc1-c2=\"; print(c3); c3=c1*c2;

cout<<\"\\nc1*c2=\";

print(c3); c3=c1/c2;

cout<<\"\\nc1/c2=\"; print(c3); cout<(三)、重载为友元函数 1、格式:

friend <类名> operator <运算符> (<参数表>)

2、重载为友元函数时,由于没有隐含this指针参数,所以双目运算符有2个参数,单目运算符,重载为友元函数时,必须说明1个参数。

3、不能重载友元函数的运算符有: = ( ) [ ] -> 例:

#include #include class string {

public:

string( ) {real=imag=0;} string(double r,double i) { real=r;imag=i; }

friend string operator +(const string &c1,const string &c2); friend string operator -(const string &c1,const string &c2); friend string operator *(const string &c1,const string &c2); friend string operator /(const string &c1,const string &c2); friend void print(const string &c); private:

double real,imag; };

string operator +(const string &c1,const string &c2) {

return string(c1.real+c2.real,c1.imag+c2.imag); }

string operator -(const string &c1,const string &c2) {

return string(c1.real-c2.real,c1.imag-c2.imag); }

string operator *(const string &c1,const string &c2) {

return string(c1.real*c2.real-c1.imag*c2.imag, c1.real*c2.imag+c1.imag*c2.real); }

string operator /(const string &c1,const string &c2) {

return string((c1.real*c2.real+c1.imag*c2.imag)/(c2.real*c2.real+c2.imag*c2.imag), (c2.real*c1.imag-c2.imag*c1.real)/(c2.real*c2.real+c2.imag*c2.imag)); }

void print(const string &c) {

if(c.imag<0) cout<void main()

{

string c1(2.0,3.0),c2(4.0,-2.0),c3; c3=c1+c2;

cout<<\"\\nc1+c2=\"; print(c3); c3=c1-c2;

cout<<\"\\nc1-c2=\"; print(c3); c3=c1*c2;

cout<<\"\\nc1*c2=\"; print(c3); c3=c1/c2;

cout<<\"\\nc1/c2=\"; print(c3); cout<例2:

#include #include class string {

public:

string( ) {x=y=0;} string(int i,int j) { x=i;y=j; }

string(string &p) {x=p.x;y=p.y;} string& operator=(string &p); int getx() {return x;} int gety() {return y;} private: int x,y; };

string& string::operator =(string &p) {

x=p.x; y=p.y;

cout<<\"assignment opterator called.\\n\"; return *this; }

void main() {

string a(7,8); string c; c=a;

cout<总之:在一般情况下,单目运算符最好重载为成员函数;对双目运算符最好被重载为友元函数。 (四)下标运算符的重载。例: #include #include class string {

public:

string(int i) { length=i;

buff=new char[length]; }

~string() {delete buff;}

int getlength() {return length;} char & operator[](int i); private: int length; char *buff; };

char & string::operator[](int i) {

static char ch=0; if(i=0) return buff[i]; else { cout<<\"\\nindex out of range.\"; return ch; } }

void main() {

int cnt;

string string1(6);

char *string2=\"string\"; for(cnt=0;cnt<8;cnt++) string1[cnt]=string2[cnt]; cout<<\"\\n\";

for(cnt=0;cnt<8;cnt++) cout<cout< #include class string {

public:

string( ) {v=0;} string operator ++(); string operator ++(int);

void print() {cout<unsigned v; };

string string::operator ++() {

v++;

return *this; }

string string::operator ++(int) {

string t; t.v=v++; return t; }

void main()

{

string str;

for(int i=0;i<8;i++) str++; str.print();

for(i=0;i<8;i++) ++str; str.print(); }

(六)、重载函数调用运算符。 例:

通过函数调用运算符的重载编程实现如下的表达式: f (x , y) = ( x+5 ) * y

#include #include class string {

public:

double operator ()(double x,double y) const; };

double string::operator ()(double x,double y) const {

return (x+5)*y; }

void main() {

string str;

cout<三、静态联编和动态联编

1、联编:是指一个程序中的操作调用与执行该操作代码间彼此关联的过程。可分为两种:静态联编和动态联编。

2、静态联编:是指联编阶段出现在编译连接阶段。

3、动态联编:是指联编阶段出现在运行阶段(通过虚函数实现)。例: #include class point {

public:

point(double i,double j) {x=i;y=j;} double area() const {return 0.0;} private:

double x,y; };

class rectangle:public point {

public:

rectangle(double i,double j,double k,double l); double area() const {return w*h;} private:

double w,h; };

rectangle::rectangle(double i,double j,double k,double l):point(i,j) {

w=k; h=l; }

void fun(point &s)

{

cout<void main() {

rectangle rec(3.0,5.2,15.0,25.0); fun(rec); }

四、虚函数:

1、虚函数是为实现某种功能而假设的函数,在函数前加上关键字vi rtual来修饰,这个函数就成了虚函数。可以通过定义虚函数来实现动态联编。

2、只有类的成员函数才能声明为虚函数,全局函数、静态函数和友元不能声明为虚函数。 3、定义方法:首先在基类和派生类中各定义一些同名函数(函数名、返回类型和参数);然后在基类的同名函数前加关键字VIRTUAL,这时不管派生类中的同名函数前是否加了VIRTUAL,它们都将变成虚函数。 4、动态联编只能通过指针或引用标示对象来操作虚函数。如果采用一般对象来操作虚函数,则采用静态联编来调用虚函数。函数被定义成虚函数后,通过定义指针或引用使指针实际指向哪个对象就调用哪个对象的成员函数(实现多态性)。例1。例2: #include class A {

public:

virtual void act1(); void act2() { act1();} };

void A::act1() {

cout<<\"A::act1() called.\"<class B:public A {

public:

void act1(); };

void B::act1() {

cout<<\"B::act1() called.\"<void main() { B c; c.act2(); }

5、构造函数调用虚函数:

构造函数中调用虚函数时,采用静态联编。即构造函数调用的虚函数是自己类中实现的虚函数。如果自己类中没有这个虚函数,则调用基类中的虚函数,而不是派生类中的虚函数。例: #include class A {

public: A() {}

virtual void f() {cout<<\"A::f() called.\"<class B:public A {

public:

B() {f();}

void g() {f();}

};

class C:public B {

public:

C() { }

virtual void f() {cout<<\"C::f() called.\"<void main() {

C c; c.g(); }

1) 举例:

i. 使用指向类的实例对象的指针编程: #include

class Person {

public:

char *KindOf() {

return \"Person\"; } };

class Man : public Person {

public:

char *KindOf() {

return \"Man\"; } };

class Women : public Person {

public:

char *KindOf() {

return \"Women\"; } };

void main() {

Man man;

Women women; Person *pPerson; Man *pMan=&man;

Women *pWomen=&women; pPerson=pMan;

cout<<\"pMan->KindOf():\"<KindOf()<cout<<\"pPerson->KindOf(): \"<KindOf()<pPerson=pWomen;

cout<<\"pWomen->KindOf(): \"<KindOf()<KindOf(): \"<KindOf()<}

ii. 使用虚函数实现多态性:

#include class Person {

public:

virtual char *KindOf() {

return \"Person\"; } };

class Man : public Person {

public:

char *KindOf() {

return \"Man\"; } };

class Women : public Person {

public:

char *KindOf() {

return \"Women\"; } };

void main() {

Man man;

Women women; Person *pPerson; Man *pMan=&man;

Women *pWomen=&women; pPerson=pMan;

cout<<\"pMan->KindOf(): \"<KindOf()<cout<<\"pPerson->KindOf(): \"<KindOf()<pPerson=pWomen;

cout<<\"pWomen->KindOf(): \"<KindOf()<KindOf(): \"<KindOf()<}

五、纯虚函数和抽象类

1、纯虚函数:特殊的虚函数。定义格式如下: virtual <类型><函数名>(<参数表>)=0;

在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它说明为纯虚函数,它的实现留给该基类的派生类去做。例: #include class point {

public:

point(int i,int j) {x0=i;y0=j;} virtual void set()=0; virtual void draw()=0; protected: int x0,y0; };

class line:public point {

public:

line(int i=0,int j=0,int m=0,int n=0):point(i,j) { x1=m;y1=n; }

void set() {cout<<\"line::set() called.\\n\";}

void draw() {cout<<\"line::draw() called.\\n\";} protected: int x1,y1; };

class ellipse:public point {

public:

ellipse(int i=0,int j=0,int p=0,int q=0):point(i,j) { x2=p;y2=q; }

void set() {cout<<\"ellipse::set() called.\\n\";}

void draw() {cout<<\"ellipse::draw() called.\\n\";} protected: int x2,y2; };

void drawobj(point *p) {

p->draw(); }

void setobj(point *p) {

p->set(); }

void main() {

line *lineobj=new line;

ellipse *ellipseobj=new ellipse; drawobj(lineobj); drawobj(ellipseobj); cout<cout<<\"\\nredarw the object .........\\n\"; drawobj(lineobj); drawobj(ellipseobj); }

2、抽象类 1)、带有纯虚函数的类称为抽象类。 2)、抽象类只能作为基类来使用,其纯虚函数的实现由派生类给出。 一、 虚析构函数

1、如果一个基类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否加了关键字virtual。

2、说明虚析构函数的目的是在使用delete运算符删除一个对象时,能确保析构以动态联编的方式来运行。例: #include class point {

public:

virtual ~point( ) { cout<<\"point::~point() called.\"<};

class line:public point {

public:

line(int i) { buf=new char[i]; }

virtual ~line() { delete [] buf; cout<<\"line::~line() called.\"<char * buf; };

void drawobj(point *p) {

delete p; }

void main() {

point *p=new line(15); drawobj(p); }

第九章 c++的I/O流库

一、前言

1、在c++中,输入输出操作是由“流”来处理的。

2、所谓流是数据流动的抽象,是指数据从一个位置流向另一个位置。 例如:键盘->程序。 程序―――>屏幕或磁盘文件

3、流在使用前要被建立,使用后要删除,还要使用一些特定的操作从流中获取数据(提取操作)或向流中添加数据(插入操作)。 4、本章主要内容: ① 屏幕输出

② 键盘输入 (一) ③ 格式化输出\\输入 ④ 重载提取符和插入符

⑤ 磁盘文件输入和输出 (二)

5、一般的输入输出操作分别由istream类和ostream类提供,而iostream类是这个类的派生类,它允许进行输入输出双向操作。Ostream类的输出操作是插入过程,由重载符“<<”来实现。 istream类的输入操作是插入过程,由重载符“>>”来实现。

另外系统还预定义了4个流类对象,供用户需要时使用: cin:用来处理标准输入,即键盘输入 cout:用来标准输出,即屏幕输出

cerr:用来标准出错信息,提供不带缓冲区的输出 clog:用来标准出错信息,提供带缓冲区的输出。 6、在c++中文件的输入输出主要用到下面5个类:

fstreambase类:一个公共基类,一般的文件操作不使用此类。 Ifstream类:对文件进行提取操作。 Ofstream:对文件进行插入操作。

Fstream:对文件进行插入或者提取操作 Filebuf类:主要用作上述类的缓冲支持。

二、屏幕输出

1、使用预定义的插入符“<<”

最一般的屏幕输出是将插入符作用在流类对象cout上。其格式是: cout<<(表达式)<<(表达式)<<。。。。。。。。。。。。。 例:#include #include void main() {

cout<<\"the lenght of \\\"this is a string\\\" is:\\"<说明: 1)、在输出语句中,可以串联多个插入运算符,输出多个数据项。 2)、在插入运算符后边可以写任意复杂的表达式,系统自动计算出它的值并传给插入符。 2、使用成员函数put()输出一个字符

成员函数put()提供了一种将字符送进输出流的方法。它可以输出字符常量,也可以输出字符变量。 其格式: cout . put(char c); 或者 cout . put(const char c); 例:#include #include void main() {

cout<<'a'<<','<<'b'<<'\\n';

cout.put('a').put(',').put('b').put('\\n'); char c1='A',c2='B';

cout.put(c1).put(c2)<3、使用成员函数write()输出一个字符串 格式: cout . write(const char * str ,int n);

其中:第一个参数可以是字符指针、字符数组,也可以是字符串常量;第二个参数输出字符串中字符的个数。 例:#include #include

void printstring(char *s) {

cout.write(s,strlen(s)).put('\\n'); cout.write(s,6)<void main() {

char str[]=\"i love c++\";

cout<<\"the string is: \"<printstring(\"this is a string\"); }

三、键盘输入

1、使用预定义的提取符“>>”

最一般的键盘输入是将提取符作用在流类的对象cin上。 格式:cin>>(表达式)>>(表达式)>>…………………

说明:在输入时,表达式与表达式之间用空白符分隔(空格符、tab键或换行符)。并且空白符本身不作为输入流中提取的字符。

例:#include #include void main()

{

int a,b;

cout<<\"please enter two integes:\"; cin>>a>>b;

cout<<\"(\"<2、使用成员函数get()获取一个字符

get()函数可以从输入流获取一个字符,并把它放置到指定的变量中。 格式: cin . get(char & ch);

其中:cin是对象,&ch是一个字符的地址值,用它来存放从输入流中所获取的字符。 例:#include #include void main() {

char ch;

cout<<\"input:\";

while((ch=cin.get())!=EOF) cout.put(ch); cout<<\"ok!\"; }

3、使用成员函数getline()从输入流获取多个字符: 格式:cin . getline(char * buf ,int limit ,deline=‘\\n‘);

其中:第一个参数是字符指针或字符数组,第2个参数限制获取字符的最大个数,第三个参数指定结束符,默认是‘\\n‘。

例:编程统计从键盘上输入每一行字符的个数,从中选取最长的行的字符个数,统计共输入多少行。 #include #include const int size=80; void main() {

int lcnt=0,lmax=-1; char buf[size];

cout<<\"input.......\\n\";

while(cin.getline(buf,size)) { int count=cin.gcount(); lcnt++; if(count>lmax) lmax=count; cout<<\"line #\"<cout<cout<<\"total line:\"<4、使用成员函数read()从输入流中获取一个字符串,并将它们放到指定的数组中。 格式: cin . read(char * buf ,int size);

其中:第一个参数是用来存放字符串的字符数组或字符指针;第2个参数是字符串的长度。 例:

#include #include void main() {

const int s=80;

char buf[s]=\"\";

cout<<\"input.........\\n\"; cin.read(buf,s); cout<cout<四、插入符和提取符的重载:用户可以对插入符‖<<‖和提取符‖>>‖进行重载来支持新的数据类型。 例:#include class date {

public:

date(int y,int m,int d) { year=y; month=m; day=d; }

friend ostream& operator <<(ostream &stream,date &dates); friend istream& operator >>(istream &stream,date &dates); private:

int year,month,day; };

ostream& operator <<(ostream &stream,date &dates) {

stream<istream& operator >>(istream &stream,date &dates) {

stream>>dates.year>>dates.month>>dates.day; return stream; }

void main() {

date cdate(1998,8,17);

cout<<\"current date:\"<>cdate;

cout<<\"new date:\"<五、格式化输入和输出:

c++I/O流库中每一种流的格式化信息是由一系列的标志位组成的,通过调用各种流类的成员函数能够设置这些标志位,进而达到控制输入输出的格式的目的。另外流类库中提供了一些操作子,也能控制输入输出的格式。 1、设置流的格式化标志

在ios类的公有成员部分定义了一些格式常量和成员函数,使用它们可以对数据格式进行转换。 1)、控制格式的标志位: 标志位 含义 输入输出 Skipws 跳过输入中的空白符 输入 Left 输出数据按输出域左对齐 输出 Right 输出数据按输出域右对齐 输出 Internal 数据的符号左对齐,数据本身右对齐,符号和数据之间为填充符 输入输出 Dec 转换基数为十进制形式 输入输出 Oct 转换基数为八进制形式 输入输出 Hex 转换基数为十六进制形式 输出 Showbase 输出的数值数据前面带有基数符号(0或0x) 输出

Showpoint 浮点数输出带有小数点 输出 Uppercase 用大写字母输出十六进制数值 输出 Showpos 正数前面带有+号 输出 Scientific 浮点数输出采用科学表示法 输出 Fixed 使用定点数形式表示浮点数 输出 Unitbuf 完成输入操作后立即刷新新流的缓冲区 输出 stdio 完成输入操作后刷新新系统的stdou、stderr 输出 2)、使用成员函数设置标志字 标志字:ios类中定义一个long型的数据成员用来记录当前格式的状态,即各个标志位的设置值,这个成员数据称为标志字。

设置标志字的成员函数有: long flags( ):返回标志字

long flags(long):使用参数值来更新标志字,返回更新前的标志字

long setf(long setbits , long field):将field所指定的标志清零,将setbits为1的位置1,返回以前的标志字。 long setf(long):设置参数所指定的那些标志的位,返回更新前的标志字。 long unsetf(long):清除参数所指定的那些标志的位,返回更新前的标志字。

注意:在ios类中,为了使用方便,定义了下面的静态类对象,用户可以直接使用: static const long basefield; 其值为del、oct、hex

static const long adjustfield; 其值为left、right、internal static const long floatfield; 其值为scientific、fixed 例:#include void main() {

cout.setf(ios::oct,ios::basefield); cout<<\"oct48--->\"<<48<\"<<48<\"<<48<cout<<\"hex32--->\"<<32<cout<<\"hex254--->\"<<254<2、格式输出函数

在ios类中定义下面的成员函数进行格式化输出: int width( ):返回当前输出数据的宽度

int width(int):设置用当前的参数值来设置输出数据的宽度。

char fill():返回当前所使用的填充字符,缺省的填充字符为空格符 char fill(char):设置填充字符为参数所规定的字符。 int precision():返回当前浮点数的有效数字的个数

int precision(int):设置浮点数输出时的有效数字的个数。 例:#include void main() {

cout<<\"12345678901234567890\\n\"; int i=1234; cout<cout.setf(ios::left,ios::adjustfield); cout<cout.setf(ios::right,ios::adjustfield); cout.precision(5); double j=12.345678; cout<3、操作子

c++I/O流类库提供了一些操作子直接被插入符和提取符操作,以简化格式化的操作。注意:操作子的成员函数定义在iomanip类中。操作子有: 操作子名 含义 输入输出 Dec 数值数据采用十进制表示 输入输出 Hex 数值数据采用十六进制表示 输入输出 Oct 数值数据采用八进制表示 输入输出 Setbase(int n) 设置数制转换为基数为n 输入输出 Ws 提取空白符 输入 Ends 插入空白符 输出 Flush 刷新与流相关联的缓冲区 输出 Resetiosflags(long) 清除参数所指定的标志位 输入输出 Setiosflags(long) 设置参数所指定的标志位 输入输出 Setfill(char) 设置填充符 输出 Setprecision(int) 设置浮点数输出的有效数字的个数 输出 Setw(int) 设置输出数据项的域宽 输出 例:#include #include void main() {

cout<<\"12345678901234567890\\n\"; int i=1234;

cout<cout<cout<cout<五、磁盘文件的输入和输出 (一)、磁盘文件的打开和关闭操作:使用fstream类中所定义的成员函数open()和close()。 1、打开文件:

方法1、在打开文件前,先说明一个fstream类的对象,再使用成员函数open()打开指定的文件。 格式:fstream 对象名;

对象名 . open (文件名,访问方式);

其中:第一个参数是要被打开的文件名,要包含路径名和扩展名。第2个参数是文件访问方式。 其访问方式见下表: 方式名 作用 In 以输入(读)方式打开文件 Out 以输出(写)方式打开文件 App 以输出追加方式打开文件 Are 文件打开时,文件指针位于文件尾 Trunc 如果文件存在,将其长度截断为0,并清除原有内容;如果文件不存在,则创建新文件。

Binary 以二进制方式打开文件,缺省时为文本方式 Nocreate 打开一个已有文件,如文件不存在,则打开文件失败 Noreplace 如果文件存在,除非设置ios::ate或ios::app,否则打开失败 Ios::in|ios::out 以读和写的方式打开文件 Ios::out|ios::binary 以二进制写的方式打开文件 Ios::in|ios::binary 以二进制读的方式打开文件。 例如:fstream outfile outfile . open(“f1.txt”,ios::out)

方法2、把文件名、访问方式作为文件标识符说明的一部分。 格式:

fstream 对象名(文件名,访问方式); 例如:fstream outfile(“f1.txt”,ios::out)

2、关闭文件:调用成员函数close()。 格式:对象名 . close() 例如:outfile . close() 例:#include #include void main() {

ofstream ostrm;

ostrm.open(\"f1.dat\"); ostrm<<120<ifstream istream(\"f1.dat\"); int n; double d;

istream>>n>>d;

cout<(二)文本文件的读写操作

对文本文件进行操作时,首先要打开文件,然后再对打开文件时设定的文件流进行操作。 例1:把文本写入指定的文件 #include #include #include void main() {

fstream outfile;

outfile.open(\"f2.dat\ if(!outfile) { cout<<\"f2.dat can`t open.\\n\"; abort(); }

outfile<<\"this is a profram.\\n\"; outfile<<\"this is a profram.\\n\"; outfile.close(); }

例2:从文本文件中读出文本信息 #include #include #include void main()

{

fstream infile;

infile.open(\"f2.dat\ if(!infile) { cout<<\"f2.dat can`t open.\\n\"; abort(); }

char s[80];

while(!infile.eof()) //判断文件是否结束 { infile.getline(s,sizeof(s)); cout<infile.close(); }

(三)二进制文件的读写操作

在打开二进制文件时,在open()函数中要加ios::binary方式。向二进制文件中写入信息,使用write()函数,从二进制文件中读取信息,使用read()函数。 例如:#include #include #include struct person {

char name[20]; double height;

unsigned short age; };

person people[4]={\"wang\

void main() {

fstream outfile,infile;

outfile.open(\"f5.txt\ if(!outfile) { cout<<\"f5.dat can`t open.\\n\"; abort(); }

for(int i=0;i<4;i++) { outfile.write((char *)&people[i],sizeof(people[i])); }

outfile.close();

infile.open(\"f5.dat\ if(!infile) { cout<<\"f5.dat canot open.\\n\"; abort(); }

for( i=0;i<4;i++) { infile.read((char *)&people[i],sizeof(people[i])); cout<infile.close(); }

(四)随机访问数据文件

1、系统读指针或者写指针来记录流的当前位置。 2、在istream类提供3个成员函数来操作读指针|: istream &istream::seekg (流中位置 );

istream &istream::seekg(偏移量 ,参照位置); streampos istream::tellg();

说明:1、流中位置、参照位置都为字节数,其中参照位置有3种选项:cur(当前位置)、beg(流的开始位置)、end(流的结尾处)。

2、tellg()函数的作用是返回当前读指针相对于流开始位置的字节数。 3、在ostream类提供3个成员函数来操作写指针|: ostream &ostream::seekp (流中位置 );

ostream &ostream::seekp(偏移量 ,参照位置); streampos ostream::tellp(); 例:#include #include #include void main() {

fstream file(\"f6.dat\ if(!file) {

cout<<\"f6.dat cannot open.\\n\"; abort(); }

for(int i=0;i<15;i++) {

file.write((char *)&i,sizeof(int)); }

streampos pos=file.tellp();

cout<<\"current byte number:\"<file.write((char *)&i,sizeof(int)); }

file.seekg(pos);

file.read((char *)&i,sizeof(int));

cout<<\"the data stored is\"<file.write((char *)&i,sizeof(int)); }

file.seekg(pos);

file.read((char *)&i,sizeof(int));

cout<<\"the data stored is \"<file.read((char *)&i,sizeof(int));

cout<<\"the data stored is\"<cout<<\"current byte number:\"<

因篇幅问题不能全部显示,请点此查看更多更全内容