83
移移移移移移移移移移 移移移C++ 移移移移 移移移移移移移移移移移移移移移移 移移移移 移移 一一 * 移移 移移 Intel 移移移移移移移移移

移动应用软件开发技术 第二讲: C++ 编程基础

  • Upload
    kris

  • View
    227

  • Download
    0

Embed Size (px)

DESCRIPTION

移动应用软件开发技术 第二讲: C++ 编程基础. 《 移动应用软件开发技术 》 课程建设小组 北京大学 二零一一年 *致谢:感谢 Intel 对本课程项目的支持. C++ 编程基础. C++ 标识符 (Identifiers) 程序设计语言中为变量、常量、类型、函数等取的名字称为标识符。 标识符由大小写字母、数字和下划线组成, 并且只能以字母或下划线开始。 例如: 9 abc 、 * abc 是不合法的标识符 注意: 标识符区分大小写 标识符长度任意 提倡使用 “ 见名知义 ” 的标识符 避免使用系统已定义的标识符(系统保留字). 关键字 - PowerPoint PPT Presentation

Citation preview

Page 1: 移动应用软件开发技术 第二讲: C++ 编程基础

移动应用软件开发技术

第二讲: C++ 编程基础

《移动应用软件开发技术》课程建设小组北京大学

二零一一年* 致谢:感谢 Intel 对本课程项目的支持

Page 2: 移动应用软件开发技术 第二讲: C++ 编程基础

C++ 编程基础

Page 3: 移动应用软件开发技术 第二讲: C++ 编程基础

–3

C++标识符 (Identifiers)• 程序设计语言中为变量、常量、类型、

函数等取的名字称为标识符。– 标识符由大小写字母、数字和下划线组成,– 并且只能以字母或下划线开始。 例如: 9abc、 *abc 是不合法的标识符

注意:– 标识符区分大小写– 标识符长度任意– 提倡使用“见名知义”的标识符– 避免使用系统已定义的标识符(系统保留字)

Page 4: 移动应用软件开发技术 第二讲: C++ 编程基础

–4

关键字• 关键字在计算机中有预定的含义。关键字又称保留字,它们不能再被用户重新定义使用。

auto bool break case catch char class const const_cast continue default delete do double else enum explicit extern false float for

friend goto if inline int long

mutable namespace new operator private protected

public register return short signed sizeof

static struct switch template this throw true try typedef typeid typename union

unsigned using virtual void volatile while

Page 5: 移动应用软件开发技术 第二讲: C++ 编程基础

–5

注释符• C++语言保留了 C 语言中以 /*开始, */ 结束的注释,这种方式适用于多行的注释

• 同时 C++语言中还提供行注释符 //,该注释在它的行结束处结束,适用于短注释。

Page 6: 移动应用软件开发技术 第二讲: C++ 编程基础

–6

数据类型

• 数据类型是不同形式的信息在内存中分配方式的基本约定(不同类型的数据在内存中占用的字节数有所不同),是构造程序的基础。

• 常量、变量甚至函数都具有自己的数据类型。

类型名 说明符

整型 int

字符型 char

浮点型 float

布尔型 bool

空值型 void

五种基本数据类型

Page 7: 移动应用软件开发技术 第二讲: C++ 编程基础

–7

类型名 字宽(字节) 范围

short [int] 2 –32768 ~ 32767

signed short [int] 2 –32768 ~ 32767

unsigned short [int] 2 0 ~ 65535

int 4 –2147483648 ~ 2147483647

signed [int] 4 –2147483648 ~ 2147483647

unsigned [int] 4 0 ~ 4294967295

long [int] 4 –2147483648 ~ 2147483647

signed long [int] 4 –2147483648 ~ 2147483647

unsigned long [int] 4 0 ~ 4294967295

char 1 –128 ~ 127

signed char 1 –128 ~ 127

unsigned char 1 0 ~ 255float 4

double 8

long double 8

void0

32 位机上各基本类型的字宽及表示范围

Page 8: 移动应用软件开发技术 第二讲: C++ 编程基础

–8

变量•变量是在程序执行过程中,其值可以改变的量 ;

•变量有 3 个基本要素:–名字–类型–值

Page 9: 移动应用软件开发技术 第二讲: C++ 编程基础

–9

变量的名字• 是一种标识符,需用遵守标识符的规则• 区分大小写

– mycar MyCar MYCAR 是三个变量名称 • 不能使用关键字作为变量名• “见名知意”• 常见命名方法:

– my_book

– myBook

– iMyBook

Page 10: 移动应用软件开发技术 第二讲: C++ 编程基础

–10

变量的类型• C++中的变量在使用前必须定义,定义变量时必须指明变量的类型及名字。

•变量的类型包含数据类型和存储类型•定义或说明变量的格式:

– < 类型说明符 > <变量名表 > ;–例如:

•static int my_car;

Page 11: 移动应用软件开发技术 第二讲: C++ 编程基础

–11

变量的值• 变量自身包含两个值:

– 变量值:变量所表示的数据值 – 地址值:变量在内存中的地址值

• 变量可以在定义时初始化,给变量赋一个初值。例如: int a=3,b=-78;

double area=67.34;• 变量赋值,或更改变量值例如: a=5 ;

• 取变量地址值:通过“ &” 运算符来获得例如 : &a;

Page 12: 移动应用软件开发技术 第二讲: C++ 编程基础

–12

• C++提供另一种形式的初始化方法。例如,前面两个语句可改写为:

int a(3) , b(-78) ; double area(67.34) ;

Page 13: 移动应用软件开发技术 第二讲: C++ 编程基础

–13

常量的定义格式定义格式: const < 类型说明符 > < 常量名 > = < 常量值 >

例如:const double pi = 3.141592653;

Page 14: 移动应用软件开发技术 第二讲: C++ 编程基础

–14

整型常量• 十进制整型常量

– 由 0~9 的数字组成,不能以 0 开头,没前缀– 例如: 201 89 等

• 八进制整型常量– 由 0~7 的数字组成,以 0 位前缀– 例如: 032 024 等

• 十六进制整型常量– 由 0~9及 a~f 字母组成, 0x或 0X 为前缀– 例如: 0x1a 0X3F 等

• 长整型常量后缀 L(l) ,无符号整型常量后缀 U(u)– 例如: 123L 12322U 223212ul

Page 15: 移动应用软件开发技术 第二讲: C++ 编程基础

–15

字符串常量• 以一对双撇号括起来的字符序列

– 例如:“ Hello world! \n”– 字符串常量中可以包含空格符、转义字符及其他字符,也可以包含汉字。

• 由于双撇号是字符串的定界符,因此字符串中使用 \” 表示双撇号。

– 字符串中字符的个数可以为任意数目– 字符串常量后面有一个结束符’ \0’

• “a” 与’ a’ 不同

Page 16: 移动应用软件开发技术 第二讲: C++ 编程基础

–16

运算符 运算符是指用来表示在数据上执行某些特定操作的符号。参与运算的数据称为操作数。(可以分别称为单目、双目和三目运算符)。

• 算术运算符• 关系运算符• 逻辑运算符• 位操作运算符• 赋值运算符• 其他运算符

Page 17: 移动应用软件开发技术 第二讲: C++ 编程基础

–17

逻辑运算真值 表(真为非 0 ,假为 0 )

a b a&&b a||b !a !b

0 0 0 0 1 1

0 非 0 0 1 1 0

非 0 0 0 1 0 1

非 0 非 0 1 1 0 0

Page 18: 移动应用软件开发技术 第二讲: C++ 编程基础

–18

位操作运算符• 位运算符是对其操作数按其二进制形式逐位进行运算,参加位运算的操作数必须为整数。

• C++ 中所有的位运算符如下:~ (按位求反) << (左移) >> (右移) & (按位与)^(按位异或) | (按位或)

Page 19: 移动应用软件开发技术 第二讲: C++ 编程基础

–19

选择语句• 利用选择语句可以实现具有选择结构的程序

• 选择语句有两种– 条件语句( if 语句)– 开关语句( switch 语句)

• 特点:具有一定的判断功能– 可以根据给定的条件来决定执行哪路分支中的语句

Page 20: 移动应用软件开发技术 第二讲: C++ 编程基础

–20

C++中有三种循环语句可用来实现循环结构: while语句、 do_while语句和 for语句。

这些语句各有各的特点,而且常常可以互相替代。在编程时应根据需要选择最适合的循环语句。

循环语句

Page 21: 移动应用软件开发技术 第二讲: C++ 编程基础

–21

转向语句• goto 无条件转向语句 ,很少使用• break 退出语句• continue 结束本次循环语句转向语句用于改变语句的执行顺序

Page 22: 移动应用软件开发技术 第二讲: C++ 编程基础

–22

枚举的定义枚举类型和枚举变量的定义格式如下,其中 enum 是枚举类型定义的关

键字。enum 枚举类型名{ 枚举常量名 1 ,

枚举常量名 2 ,…

} 枚举变量 ; // 在定义枚举类型的同时定义枚举变量。

例如:enum WeekDay{

Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday

}today;

也可在枚举类型定义后再定义枚举变量,格式如下:枚举类型名 枚举变量。如: WeekDay tomorrow;

Page 23: 移动应用软件开发技术 第二讲: C++ 编程基础

–23

枚举类型void main(){

enum WeakDay{Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday };

WeakDay Today;Today=Friday;cout<<"Today="<<Today<<endl;Today=Sunday;cout<<"Today="<<Today<<endl;

}

Today=5Today=0

Page 24: 移动应用软件开发技术 第二讲: C++ 编程基础

–24

756 -23 54 …… 107

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

图 一维数组

数组是一些意义上相关的同类型变量的有序集合。

每个数组元素都是一个变量,用来存放不同的值。

数组元素引用形式: 数组名 [ 下标 ]

数组

Page 25: 移动应用软件开发技术 第二讲: C++ 编程基础

指针的概念1.指针: 即变量的内存地址。2.指针变量 指针变量是一种特殊的变量: 它存放的不是数据的值,而是另一个变量

的地址。

指针变量常常直接简称为指针。

 

指针

Page 26: 移动应用软件开发技术 第二讲: C++ 编程基础

–26

一个指针在定义以后,并不具体地指向某个变量,而只是确定了类型。可以对指针进行初始化,让它指向某个具体的变量。

“&” 是取地址运算符,用在一个存储器操作数的前面,表示取存储器操作数的地址值。例如:

float salary ; float *salary_ptr = &salary ; 就将指针 salary_ptr 初始化为变量 salary 的地址值,也即

指向了具体的 salary 。

Page 27: 移动应用软件开发技术 第二讲: C++ 编程基础

–27

指针的赋值和引用

除了在指针定义时对它进行初始化外,还可以使用赋值运算来给指针赋以变量的地址值。例如:

int a = - 8978 ; int *p ; p = &a ; 这里, p 被赋值为变量 a 的地址。

也可以将一个已被赋值的指针赋给另一个相同类型的指针。例如:

double a ; double *x = &a , *y ; y = x ; 这样一来, y 就与 x 指向同一个变量 a 。

Page 28: 移动应用软件开发技术 第二讲: C++ 编程基础

–28

一个关于指针的例子。 # include <iostream.h> void main() { int x = 50 ; int *x_ptr = &x ; // x_ptr 指向 x cout << " x = " << x << endl ; // 输出 x 的值 cout << " *x_ptr = " << *x_ptr << endl ;

// 输出 x_ptr 所指单元的值 cout << " x_ptr = " << x_ptr << endl ;

// 输出 x_ptr 的值 *x_ptr = 100 ; cout << " x = " << x << endl ; cout << " *x_ptr = " << *x_ptr << endl ; cout << " x_ptr = " << x_ptr << endl ; }

程序的输出为: x = 50 *x_ptr = 50 x_ptr = 0x0065FDF4 x = 100 *x_ptr = 100 x_ptr = 0x0065FDF4

Page 29: 移动应用软件开发技术 第二讲: C++ 编程基础

–29

指针与整数进行的加、减运算,代表着指针在内存空间上、下移动。具体上移或下移的字节数与其类型密切相关。

例如,假设在某字长为 32 的计算机中,一个 int 型数据占 4个字节,如果有

int a = 78 ; int *x = &a ; x 初始化为指向变量 a 。在语句 x = x + 1 ; 执行后, x 中存放的地址值被加了 4 ,指向变量 a 下面一个

整数。同理,语句 x = x – 1 ; 执行后, x 指向了上一个整数。

指 针 运算

Page 30: 移动应用软件开发技术 第二讲: C++ 编程基础

–30

当 ++ 或– –与 * 同时作用于指针时,同样应该注意运算的顺序。

例如 : x = *p++ ; 相当于 x = *(p++) ; 即先从当前地址中取值,然后将指针指向下

一个数据。又如 : x = *++p ; 相当于 x = *(++p) ;

先将地址加 1 ,再取地址中的数据赋给 x 。而 x = ++*p ; 相当于 x = ++(*p) ;

表示先取 p 所指向的单元内的数据值,再将数据值加 1 后赋给 x 。

Page 31: 移动应用软件开发技术 第二讲: C++ 编程基础

–31

例:给出程序的运行结果#include <iostream.h> void main() {

int a[3] = {24,30,8}; int *p;p=a;int x;x=*p++;cout<<x<<","<<*p<<endl;x=*++p;cout<<x<<","<<*p<<endl;x=++*p;cout<<x<<","<<*p<<endl;

}

24,308,89,9

Page 32: 移动应用软件开发技术 第二讲: C++ 编程基础

–32

函数定义与函数原型

C++ 中的函数由一段 相 对 独 立 的 程 序组 成 , 这 段 程 序 能实 现 某 一 方 面 独 立和完整的功能。

例 求 5 ! +4 !#include<iostream.h> int factorial(int n) {

int z,i;z=1;

for (i=1;i<=n;i++) z=z*i;return z;

}void main(){

int x;x= factorial (5)+ factorial (4);cout<<”5 ! +4 ! =”<<x<<endl;

}

程序运行结果:5 ! +4 ! =144

Page 33: 移动应用软件开发技术 第二讲: C++ 编程基础

(1) 形式参数:在被调用函数名后面的()内的变量称为形式参数(简称“形参”)。(2) 实际参数:在调用函数名后面的()内中的表达式或变量称为实际参数(简称实参)。

例 求从键盘上输入的两数中的最大值#include<iostream.h>void max(int x,int y);void main(){

int a,b;cout<< "Please input two integers: "; cin>>a>>b;max(a,b);

}void max(int x,int y){

int w; w=x>y? x:y;

cout<<"The big one of two input number is :"<<w<<endl;

}

运行结果:

Please input two integers: 54 -89

The big one of two input number is :54

程序中 x, y 为形参, a, b 为实参。

Page 34: 移动应用软件开发技术 第二讲: C++ 编程基础

–34

函数的传值调用

例 交换两个整数变量的值。#include<iostream.h>void exch(int x, int y){

int z;z=x;x=y;y=z;

}

void main(){

int a=3, b=5;exch(a,b);cout<<"a="<<a<<", b="<<b<<endl;

} // 运行结果: a=3, b=5

变量 a,b 的值没有改变。

Page 35: 移动应用软件开发技术 第二讲: C++ 编程基础

–35

函数的传址调用 传址调用 : 指针作函数参数

例 交换两个整数变量的值。#include<iostream.h>void exch(int *x, int *y){

int z;z=*x;*x=*y;*y=z;

}

void main(){

int a=3, b=5;exch(&a,&b);cout<<"a="<<a<<", b="<<b<<endl;

}

// 运行结果: a=5, b=3

变量 a, b 的值已经交换。

Page 36: 移动应用软件开发技术 第二讲: C++ 编程基础

–36

动态内存分配

在 ANSI C 中, malloc ( )和 free( )

C++兼容了 C 语言中的这两个函数,并提供了两个新的操作符: new 和 delete

C++ 程序运行时可以在内存区使用new运算符和 delete运算符动态创建和删除变量。

Page 37: 移动应用软件开发技术 第二讲: C++ 编程基础

–37

//动态分配#include "stdio.h“ //包含标准输入输出头文件#include "stdlib.h" //包含动态存储分配函数头文件

void main(){int *p; // 定义一个整型指针 p

// 为指针 p 动态分配一个存储单元p = (int *)malloc(sizeof(int));*p = 6; //将 6赋给指针 p指向的存储单元printf("%d",*p);free(p); // 释放 p 所指向的存储单元

}

Page 38: 移动应用软件开发技术 第二讲: C++ 编程基础

–38

• 例内存动态分配程序#include <iostream.h>void main(){

int *pc;cout<<"pc="<<pc<<endl;pc=new int;cout<<"pc="<<pc<<endl;*pc=10;cout<<"pc="<<pc<<endl;cout<<"*pc="<<*pc<<endl;delete pc;

}

0pc

Page 39: 移动应用软件开发技术 第二讲: C++ 编程基础

–39

• 对于数组进行动态分配的格式为:– 指针变量名 =new 类型名 [ 下标表达式 ];– delete [ ] 指向该数组的指针变量名 ;

• 两式中的方括号是非常重要的,两者必须配对使用,如果 delete语句中少了方括号,因编译器认为该指针是指向数组第一个元素的指针,会产生回收不彻底的问题(只回收了第一个元素所占空间),加了方括号后就转化为指向数组的指针,回收整个数组。 delete [ ]的方括号中不需要填数组元素数,系统自知。即使写了,编译器也忽略。

• 请注意“下标表达式”不是常量表达式,即它的值不必在编译时确定,可以在运行时确定。

Page 40: 移动应用软件开发技术 第二讲: C++ 编程基础

–40

【例 】动态数组的建立与撤销#include <iostream.h>#include <string.h>void main(){

int n;char *pc;cout<<" 请输入动态数组的元素个数 "<<endl;cin>>n; // 在运行时确定,可输入 17pc=new char[n];

// 申请 17 个字符(可装 8 个汉字和一个结束符)的内存空间strcpy(pc," 堆内存的动态分配 ");cout<<pc<<endl;delete []pc;// 释放 pc 所指向的 n 个字符的内存空

间}

Page 41: 移动应用软件开发技术 第二讲: C++ 编程基础

–41

结构定义格式:struct 结构名{ 类型 1 结构成员 1 ;

类型 2 结构成员 2 ;…;

};

例如:struct Teacher{

long int id;

char name[10] ;int age;int sex;

}; 结构定义后,可以声明结构变量或指向结构的指针如:

Teacher Zhang;Teacher *tp;tp=new Teacher;

Page 42: 移动应用软件开发技术 第二讲: C++ 编程基础

–42

类• 类是具有相同属性和行为的一组对象的集合,它为属于该类的全部对象提供了统一的抽象描述,其内部包括属性和行为两个主要部分。

• 利用类可以实现数据的封装、隐藏、继承与派生。

• 利用类易于编写大型复杂程序,其模块化程度比 C 中采用函数更高。

Page 43: 移动应用软件开发技术 第二讲: C++ 编程基础

–43

• 类的定义分为说明和实现两个部分。

• 类说明部分是用来声明该类中的成员。类的成员包括数据成员和函数成员。其中,函数成员又称成员函数或“方法”,用于对数据成员进行各种操作。

• 类实现部分用来对成员函数进行定义。• 即说明部分告诉类要“干什么”,实现部分告诉类“怎么干”。

Page 44: 移动应用软件开发技术 第二讲: C++ 编程基础

–44

类说明部分类说明部分一般格式如下:class 类名{

private:(或缺省时 )数据成员声明或函数成员的原型;

protected:数据成员声明或函数成员的原型;

public:数据成员声明或函数成员的原型;

} ;

Page 45: 移动应用软件开发技术 第二讲: C++ 编程基础

–45

类实现部分

类的实现部分,包括所有在类体中说明的成员函数的定义。成员函数的定义通常在类定义体之外给出,其中每个成员函数定义格式为:返回值类型 类名::成员函数名( < 参数表 > ){

… //函数体} 类的成员函数在类外部定义时,前面必须加上“类名::”,以说明所定义的函数是哪一个类的成员。“::”称为作用域运算符。

Page 46: 移动应用软件开发技术 第二讲: C++ 编程基础

–46

封装性来自对类成员的访问控制权限。 在 C++中,类的成员从访问权限上分为私有( private )、公有( public )和保护( protected)三类。 私有成员通常是一些数据成员。 private权限为类带来了封装性,它使私有成员隐藏起来,不能从类的外部对它们进行访问,或者说它们从类外部是不可见的,只有类自己的成员函数才可以访问它们。 公有成员往往是一些操作(即成员函数),可在程序中类的外部访问它们,它们是类的对外接口。

类封装和数据隐藏

Page 47: 移动应用软件开发技术 第二讲: C++ 编程基础

–47

例: 点类 Point的定义

class Point{

private :double x , y ;

public :void SetPoint(double x , double y) ;

double GetX ( ) ;double GetY ( ) ;

void Print ( ) ;

} ;

void Point :: SetPoint (double a , double b) // 定义成员函数 SetPoint( ){ x = a ; y = b; }double Point :: GetX ( ) // 定义成员函数 GetX ( ){ return x ;}double Point :: GetY ( ) // 定义成员函数 GetY ( ){ return y ;}void Point :: Print( ) // 定义成员函数 Print( ){ cout<<”X=”<< x <<”,”<< “Y=”<< y <<endl ;}

类实现部分:

类说明部分:

Page 48: 移动应用软件开发技术 第二讲: C++ 编程基础

–48

定 义 类 时 说 明 部 分 中 的 关 键 字public、 private、 protected从它们出现的位置起开始生效,直到出现另一个访问权限关键字为止。

访问权限关键字可以按任意顺序出现任意次,但是,如果把所有的私有成员和公有成员归类放在一起,能增强程序的可读性。

如果把所有的私有成员放在公有成员前面,可以自动获得缺省访问控制权限 private。

Page 49: 移动应用软件开发技术 第二讲: C++ 编程基础

–49

类中的数据成员可以是任何数据类型。例如整型、浮点型、字符型、数组、指针和引用等。 不能在类的说明部分给类的数据成员赋初值,例如在点类的定义中,下面的定义是错的:class Point{

int x=0 , y=0;public:

┆};

Page 50: 移动应用软件开发技术 第二讲: C++ 编程基础

–50

对象的定义和成员表示 类描述了对象的数据存储和操作特性,对象是类的实例。正像定义 int 类型的变量一样,创建类类型 Point 的对象也被看作定义 Point 类型的变量。

对象在它的类确定了以后,定义格式为: 类名 < 对象名表 > 例如,定义 ( 或者说创建 ) 两个点类 Point 的对象:

Point p1 , p2 (2.0 , 3.0) ; < 对象名表 > 中,可以是一般的对象名,也可以是指向对象的指针或对象的引用,还可以是对象数组名。例如,一个复数类 Complex 的对象可以如下定义:

Complex c1, c2 , *pc, c[10] ;

Page 51: 移动应用软件开发技术 第二讲: C++ 编程基础

–51

对象成员的表示方法 一个对象的成员就是该对象的类所定义的成员。

对象成员有数据成员和成员函数。 一般对象的成员表示如下: < 对象名 >.< 成员名 > 或者 < 对象名 >.< 成员名 >(< 参数表 >) 前者用来表示数据成员,后者用来表示成员函数

。这里的“ .” 是一个运算符,该运算符的功能是表示对象的成员。 指向对象的指针的成员表示如下: < 对象指针名 >->< 成员名 > 或者 < 对象指针名 >->< 成员名 >(< 参数表 >) 这里的“ ->” 是一个表示成员的运算符,它与

“ .” 运算符的区别是“ ->” 用来表示对象的指针的成员,而“ .” 用来表示一般对象的成员。同样,前者表示数据成员,而后者表示成员函数。

Page 52: 移动应用软件开发技术 第二讲: C++ 编程基础

–52

#include <iostream.h>#include "cdate.h"void main(){ CDate date1, date2; date1.SetDate(1996,5,4); date2.SetDate(1998,4,9); int

leap=date1.IsLeapYear(); cout<<leap<<endl; date1.Print(); date2.Print();}

例 分析该程序的输出结果class CDate{ public: void SetDate(int y, int m, int d); int IsLeapYear(); void Print(); private: int year, month, day;};void CDate::SetDate(int y, int m, int d){ year=y; month=m; day=d;}int CDate::IsLeapYear(){ return (year%4==0&&year%100!=0)||(year

%400==0);}void CDate::Print(){ cout<<year<<"."<<month<<"."<<day<<endl;}

Page 53: 移动应用软件开发技术 第二讲: C++ 编程基础

–53

构造函数与析构函数• 构造函数和析构函数是在类体中说明的两种特殊的成员函数。

• 构造函数的功能是在创建对象时,用给定的对象对对象进行初始化。

• 析构函数的功能是用来释放一个对象,它与构造函数的功能正好相反。

Page 54: 移动应用软件开发技术 第二讲: C++ 编程基础

–54

构造函数的特点如下:(1)构造函数是成员函数,函数体可写在类体内,

也可写在类体外。(2)构造函数是一个特殊的成员函数,该函数的名

字与类名相同,该函数不指定类型说明。该函数可以没有参数,也可有参数。

(3)构造函数可以重载,即可定义多个参数个数不同的函数。

(4)程序中一般不直接调用构造函数,在创建对象时系统自动调用构造函数。

Page 55: 移动应用软件开发技术 第二讲: C++ 编程基础

–55

构造函数举例

class Clock

{

public:

Clock (int NewH, int NewM, int NewS);// 构造函数void SetTime(int NewH, int NewM, int NewS);

void ShowTime();

private:

int Hour,Minute,Second;

};

Page 56: 移动应用软件开发技术 第二讲: C++ 编程基础

–56

构造函数的实现:Clock::Clock(int NewH, int NewM, int NewS)

{

Hour= NewH;

Minute= NewM;

Second= NewS;

}

建立对象时构造函数的作用:void main()

{

Clock c (0,0,0); //隐含调用构造函数,将初始值作为实参。 c.ShowTime();

}31

Page 57: 移动应用软件开发技术 第二讲: C++ 编程基础

–57

析构函数

• 完成对象被删除前的一些清理工作。• 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。

• 如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数。

Page 58: 移动应用软件开发技术 第二讲: C++ 编程基础

–58

构造函数和析构函数举例#include<iostream>using namespace std;class Point{ public: Point(int xx,int yy); ~Point(); //...其它函数原形 private: int X,int Y;};

Page 59: 移动应用软件开发技术 第二讲: C++ 编程基础

–59

Point::Point(int xx,int yy)

{ X=xx; Y=yy;

}

Point::~Point()

{

}

//...其它函数的实现略

41

Page 60: 移动应用软件开发技术 第二讲: C++ 编程基础

–60

继承是 C++ 实现软件重用的主要手段。

计程车 公共汽车 旅游车

汽车

客车 货车 工程车

交通工具类层次关系图

Page 61: 移动应用软件开发技术 第二讲: C++ 编程基础

–61

派生 (Derivate) 类的定义格式

派生类的定义格式为:class 派生类名: 继承方式 基类名{

//派生类新增成员定义…

}; “ 继承方式”用于规定派生类中由基类继承到的那部分成员在派生类中的访问控制权限。继承方式用下述三个关键字之一来指定: public :公有继承; protected :保护继承;private :私有继承。

Page 62: 移动应用软件开发技术 第二讲: C++ 编程基础

–62

继承方式 基类特性 派生类特性

Public继承

public public

protected protected

private 不可访问

Private继承

public private

protected private

private 不可访问

Protected继承

public protected

protected protected

private 不可访问

Page 63: 移动应用软件开发技术 第二讲: C++ 编程基础

–63

class <派生类名 >:<继承方式 1><基类名1>,<继承方式 2><基类名 2>,…

{    < 派生类新定义成员 >};

多继承与单继承的区别从定义格式上看,主要是多继承的基类多于一个。

Page 64: 移动应用软件开发技术 第二讲: C++ 编程基础

–64

派生类构造函数的一般格式如下:派生类构造函数的一般格式如下:< 派生类名 >(<派生类构造函数总参数表 >):<基类构造函数 >(参数表 1),<子对象名 >(<参数表2>){    <派生类中数据成员初始化 >};派生类构造函数的调用顺序如下: · 基类的构造函数 · 子对象类的构造函数 ( 如果有的话 )    · 派生类构造函数 执行的顺序是:先祖先 ( 基类 ) ,再客人 ( 成员对象 ) ,后自己 ( 派生类 ) 。

Page 65: 移动应用软件开发技术 第二讲: C++ 编程基础

–65

派生类构造函数实例

#include<iostream.h>class A{ // 定义基类private:

int a ;public: A(int x) { a = x ;cout<<"A's constructor called."<<endl ; } void show( ) { cout<<a<<endl;}};

class B{ // 定义另一个类private:

int b ;public: B(int x) { b = x ;cout<<"B's constructor called."<<endl ; } int get( ) { return b;}};

Page 66: 移动应用软件开发技术 第二讲: C++ 编程基础

–66

派生类构造函数实例 class C : public A{ // 定义派生类private:

int c;B obj_b ;

public:C( int x ,int y , int z):A(x),obj_b(y)// 派生类构造函数{

c = z ;cout<<"C's constructor called."<<endl ;

} void show( ) { A::show( );

cout<<obj_b.get()<<","<<c<<endl ;}

}; void main( ){C c1(1,2,5), c2(3,4,7);c1.show( ) ;c2.show( ) ;

}

程序输出如下:A's constructor called.B's constructor called.C's constructor called.A's constructor called.B's constructor called.C's constructor called.12,534,7

程序输出如下:A's constructor called.B's constructor called.C's constructor called.A's constructor called.B's constructor called.C's constructor called.12,534,7

Page 67: 移动应用软件开发技术 第二讲: C++ 编程基础

–67

派生类析构函数实例#include<iostream.h>class X{

int x1,x2 ;public:

X (int i,int j) {x1 = i ; x2 = j ;}void print ( ) { cout<<x1<<”,”<<x2<<endl ; }~X( ) {cout<<”X’s destructor called.”<<endl; }

};class Y:public X{

int y ; // 派生类 Y新增数据成员public:

Y( int i , int j , int k) : X(i , j) { y = k ;}//派生类构造函数void print( ) {X::print ( ) ;cout<<y<<endl ;}~Y( ) { cout<<”Y’s destructor called.”<<endl ; }

};

void main( ){ Y y1(5,6,7) , y2(2,3,4) ; y1.print( ) ; y2.print ( ) ;}

程序输出结果如下:5 , 672 , 34Y’s destructor called.X’s destructor called.Y’s destructor called.X’s destructor called.

Page 68: 移动应用软件开发技术 第二讲: C++ 编程基础

68

A{a} A{a}

B1{b1} B2{b2}

C{ c,f1(),f2(),print() }

A::a

B1::b1

A::a

B2::b2

C::c

重复继承关系及其内存映象

(a) (b)

在上例中若声明: C c1 ; 则对继承的数据成员 a 的访问 c1.a ; 或 c1.A::a ;都会出现二义性。系统将没有足够的信息区分是访问B1中的 a ,还是B2中的 a 。派生类C的对象 c1中保存了间接基类A的成员 a 的两份拷贝。为避免出现这种二义性,可以用作用域运算符::加以限定。例如:

c1.B1::a ;c1.B2 :: a ;要想从根本上消除这种二义性,应想法使这个公共基类在间接派生类中只产生一个

该公共基类的子对象。这就需要将这个公共基类定义为虚基类。

重复继承及其二义性

Page 69: 移动应用软件开发技术 第二讲: C++ 编程基础

69

虚基类与普通基类的区别只有在发生重复继承时才能表现出来:被重复继承的基类被说明为虚基类后,其成员在派生类中只产生一个唯一的副本,这就从根本上解决了二义性问题。

虚基类的说明是在派生类的定义中进行,其说明的语法格式如下:class 派生类名: virtual 继承方式 基类名} …;}其中, virtual 是说明虚基类的关键字。虚基类的说明是在定义派生类时,写在派生类名的后面。

Page 70: 移动应用软件开发技术 第二讲: C++ 编程基础

70

虚基类的说明class A{protected:

int a;public:

A( );void f( );

};class B1: virtual public A{protected:

int b1;};class B2: virtual public A{protected:

int b2;};

class c: public B1, public B2{private:

int c;public:

C( );int g( );

}

A{f( ),a}

B1{b1} B2{b2}

C{g( ),c}

含有虚基类时的类层次关系图

Page 71: 移动应用软件开发技术 第二讲: C++ 编程基础

–71

函数重载的区分机制

1.用参数区分函数重载的不同调用版本重载函数靠参数不同而区分不同调用版本。决定参数是否相同有参数个数、参数类型等要素。如 length () 函数的重载说明:int length (int x);int length (int x, int y);double length (double x1, double x2, double y1, double y2);这三个函数,由于它们的函数名相同,参数不同而成为重载函数,与它们返回值类型相同并无关系。int sum (int x, int y); 和double sum (int a, int b); 这两个函数不是重载函数,因为它们参数个数和类型都相同,尽管它们的返回值类型不同、形式参数名也不同。编译程序认为它们是对一个函数的重新定义 (override)

另外不同的参数传递方式也无法区分重载函数,如:

int func1(int value);int func1(int &value);不能作为重载函数。

Page 72: 移动应用软件开发技术 第二讲: C++ 编程基础

–72

虚函数定义:

在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数 语法:

virtual 函数返回类型 函数名(参数表) { 函数体 }

用途:实现多态性,通过指向派生类对象的基类对象

指针或对象引用,访问派生类中同名覆盖成员函数,

Page 73: 移动应用软件开发技术 第二讲: C++ 编程基础

–73

•说明:–虚函数是一个类的成员函数–关键字 virtual 指明该成员函数为虚函数。–当某一个类的一个类成员函数被定义为虚函数,

则由该类派生出来的所有派生类中,该函数始终保持虚函数的特征。

–当在派生类中重新定义虚函数( overriding a virtual function,亦译作超载或覆盖)时,不必加关键字 virtual 。但重新定义时不仅要同名,而且它的参数表和返回类型全部与基类中的虚函数一样。

Page 74: 移动应用软件开发技术 第二讲: C++ 编程基础

–74

例#include <iostream.h> class Pet // 基类{public: virtual void Speak() { cout<<"How does a pet speak ? "<<endl; } };class Cat : public Pet //派生类{public:

virtual void Speak() { cout<<"miao!miao!"<<endl; }};class Dog : public Pet //派生类{public:

virtual void Speak() { cout<<“wang!wang!"<<endl; }};

void main(){ Pet obj,*p1; // 基类对象指针 p1, 基类对象 obj

Dog dog1; Cat cat1; obj = dog1;// 用 Dog 类对象给 Pet 类对象赋值obj.Speak();

p1=&cat1; p1->Speak();

}

这个程序将输出结果如下:How does a pet speak ?miao!miao!对 于 函 数 obj.Speak() 调 用 语句是静态绑定的(静态联编)。对于 p1->Speak() 调用语句是动态联编。

这个程序将输出结果如下:How does a pet speak ?miao!miao!对 于 函 数 obj.Speak() 调 用 语句是静态绑定的(静态联编)。对于 p1->Speak() 调用语句是动态联编。

Page 75: 移动应用软件开发技术 第二讲: C++ 编程基础

–75

动态联编( dynamic binding )亦称滞后联编( late binding ),对应于静态联编( static binding )。

如果使用对象名和点成员选择运算符“ .”引用特定的一个对象来调用虚函数,则被调用的虚函数是在编译时确定的(称为静态联编)

如果使用基类指针或引用指明派生类对象,使用该指针调用虚函数(成员选择符用箭头号“ ->” ),则程序动态地(运行时)选择该派生类的虚函数,称为动态联编。

Page 76: 移动应用软件开发技术 第二讲: C++ 编程基础

–76

纯虚函数是在基类中只有说明而没有实现定义的虚函数,它的任何派生类都必须定义自己的实现版本。普通的虚函数在派生类中可以不重新定义。此时指向派生类对象的指

针调用该函数时调用的是基类中定义的版本。纯虚函数定义形式:virtual 类型 函数名(参数表) =0;例如:在前面例子中对于从 Circle 、 Triangle 、 Rectangle抽象出的

公共基类 Figure ,求面积的运算是无实际意义的:virtual void area(){ cout<<"Can't define area for an abstraction

figure"<<endl; }area() 可以定义为纯虚函数。

纯虚函数

Page 77: 移动应用软件开发技术 第二讲: C++ 编程基础

–77

抽象类•说明

凡是包含纯虚函数的类都是抽象类。或至少带有一个纯虚函数的类称为抽象类。

因为纯虚函数是不能被调用的,包含纯虚函数的类是无法建立对象的。

抽象类的作用是作为一个类族的共同基类,或者说,为一个类族提供一个公共接口。

Page 78: 移动应用软件开发技术 第二讲: C++ 编程基础

–78

异常处理的基本思想• 计算机程序在机器上运行时会产生错误,这些错误对于编程人员可以预料到但却无法避免。

• 在一个小型程序中,一旦程序运行时发生了异常,一般是将程序立即中断运行,从而无条件释放所有资源。而在一个较为复杂的软件中,函数与函数之间存在着各自明确的功能和相互间复杂的调用关系,发现错误的函数又并不具备处理错误的能力。

Page 79: 移动应用软件开发技术 第二讲: C++ 编程基础

–79

• C++ 的异常处理机制使得异常的引发和处理不需要在同一函数内完成,它可以将异常向上传播,这样底层的函数可以专门用以解决具体问题,而上层的调用者就可以在适当的位置针对不同类型的异常设计处理。

异常处理的基本思想

Page 80: 移动应用软件开发技术 第二讲: C++ 编程基础

–80

异常处理的机制• C++ 语言提供了对处理异常情况的内部支持。在 C++ 语言中, try、 throw和catch 语句就是用于实现异常处理的机制。有了 C++ 程序的异常处理机制,程序可以向更高的执行上下文传递意想不到的事件,使 C++ 程序能更好地从各种异常事件中进行有效地恢复,从而更好地执行

Page 81: 移动应用软件开发技术 第二讲: C++ 编程基础

–81

try{ //错误侦测区块 复合语句 throw 异常类型表达式 ; // 如果发生错误用 throw 语句抛出异常}catch (异常类型 1 ){ //错误处理区块 复合语句}catch (异常类型 2 ){ //错误处理区块 复合语句} ……catch(…) // 如果在前面并没有列举异常类型,则由此处理区块处理{ //错误处理区块 复合语句} //try-throw-catch 后继续执行

异常处理的机制

Page 82: 移动应用软件开发技术 第二讲: C++ 编程基础

–82

#include <iostream>using namespace std;int try_modulus(int,int);void main(){ try //代码保护段

{ cout<<"Modulus(5,2) is "<<try_modulus(5,2)<<endl;cout<<"Modulus(3,0) is "<<try_modulus(3,0)<<endl;cout<<"Modulus(8,5) is "<<try_modulus(8,5)<<endl;

}catch(char *s) // 处理异常{cerr<<s;}cout<<"end of the program.\n";

}int try_modulus(int x,int y){ if(y==0) //检查被除数是否为零 , 是则抛出异常

throw("exception of dividing zero!\n");return x%y;

}

Modulus(5,2) is 1exception of dividing zero!end of the program

Page 83: 移动应用软件开发技术 第二讲: C++ 编程基础

Q&A

本讲结束 !